comparison lib/GeoTemCo/platin.js~ @ 0:b57c7821382f

initial
author Dirk Wintergruen <dwinter@mpiwg-berlin.mpg.de>
date Thu, 28 May 2015 10:28:12 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:b57c7821382f
1 (function($){
2
3 var jQuery = $;
4 /*
5 * basic.js
6 *
7 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 3 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301 USA
23 */
24
25 /**
26 * basic code which is included first for the minified version
27 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
28 * @release 1.0
29 * @release date: 2012-07-27
30 * @version date: 2012-07-27
31 */
32
33 var arrayIndex = function(array, obj) {
34 if (Array.indexOf) {
35 return array.indexOf(obj);
36 }
37 for (var i = 0; i < array.length; i++) {
38 if (array[i] == obj) {
39 return i;
40 }
41 }
42 return -1;
43 }
44 var GeoTemCoMinifier_urlPrefix;
45 for (var i = 0; i < document.getElementsByTagName("script").length; i++) {
46 var script = document.getElementsByTagName("script")[i];
47 var index = script.src.indexOf("platin.js");
48 if (index == -1) {
49 index = script.src.indexOf("platin-min.js");
50 }
51 if (index != -1) {
52 GeoTemCoMinifier_urlPrefix = script.src.substring(0, index);
53 break;
54 }
55 }
56 // Copyright 2006 Google Inc.
57 //
58 // Licensed under the Apache License, Version 2.0 (the "License");
59 // you may not use this file except in compliance with the License.
60 // You may obtain a copy of the License at
61 //
62 // http://www.apache.org/licenses/LICENSE-2.0
63 //
64 // Unless required by applicable law or agreed to in writing, software
65 // distributed under the License is distributed on an "AS IS" BASIS,
66 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
67 // See the License for the specific language governing permissions and
68 // limitations under the License.
69
70
71 // Known Issues:
72 //
73 // * Patterns are not implemented.
74 // * Radial gradient are not implemented. The VML version of these look very
75 // different from the canvas one.
76 // * Clipping paths are not implemented.
77 // * Coordsize. The width and height attribute have higher priority than the
78 // width and height style values which isn't correct.
79 // * Painting mode isn't implemented.
80 // * Canvas width/height should is using content-box by default. IE in
81 // Quirks mode will draw the canvas using border-box. Either change your
82 // doctype to HTML5
83 // (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
84 // or use Box Sizing Behavior from WebFX
85 // (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
86 // * Non uniform scaling does not correctly scale strokes.
87 // * Optimize. There is always room for speed improvements.
88
89 // Only add this code if we do not already have a canvas implementation
90 if (!document.createElement('canvas').getContext) {
91
92 (function() {
93
94 // alias some functions to make (compiled) code shorter
95 var m = Math;
96 var mr = m.round;
97 var ms = m.sin;
98 var mc = m.cos;
99 var abs = m.abs;
100 var sqrt = m.sqrt;
101
102 // this is used for sub pixel precision
103 var Z = 10;
104 var Z2 = Z / 2;
105
106 /**
107 * This funtion is assigned to the <canvas> elements as element.getContext().
108 * @this {HTMLElement}
109 * @return {CanvasRenderingContext2D_}
110 */
111 function getContext() {
112 return this.context_ ||
113 (this.context_ = new CanvasRenderingContext2D_(this));
114 }
115
116 var slice = Array.prototype.slice;
117
118 /**
119 * Binds a function to an object. The returned function will always use the
120 * passed in {@code obj} as {@code this}.
121 *
122 * Example:
123 *
124 * g = bind(f, obj, a, b)
125 * g(c, d) // will do f.call(obj, a, b, c, d)
126 *
127 * @param {Function} f The function to bind the object to
128 * @param {Object} obj The object that should act as this when the function
129 * is called
130 * @param {*} var_args Rest arguments that will be used as the initial
131 * arguments when the function is called
132 * @return {Function} A new function that has bound this
133 */
134 function bind(f, obj, var_args) {
135 var a = slice.call(arguments, 2);
136 return function() {
137 return f.apply(obj, a.concat(slice.call(arguments)));
138 };
139 }
140
141 var G_vmlCanvasManager_ = {
142 init: function(opt_doc) {
143 if (/MSIE/.test(navigator.userAgent) && !window.opera) {
144 var doc = opt_doc || document;
145 // Create a dummy element so that IE will allow canvas elements to be
146 // recognized.
147 doc.createElement('canvas');
148 doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
149 }
150 },
151
152 init_: function(doc) {
153 // create xmlns
154 if (!doc.namespaces['g_vml_']) {
155 doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
156 '#default#VML');
157
158 }
159 if (!doc.namespaces['g_o_']) {
160 doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
161 '#default#VML');
162 }
163
164 // Setup default CSS. Only add one style sheet per document
165 if (!doc.styleSheets['ex_canvas_']) {
166 var ss = doc.createStyleSheet();
167 ss.owningElement.id = 'ex_canvas_';
168 ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
169 // default size is 300x150 in Gecko and Opera
170 'text-align:left;width:300px;height:150px}' +
171 'g_vml_\\:*{behavior:url(#default#VML)}' +
172 'g_o_\\:*{behavior:url(#default#VML)}';
173
174 }
175
176 // find all canvas elements
177 var els = doc.getElementsByTagName('canvas');
178 for (var i = 0; i < els.length; i++) {
179 this.initElement(els[i]);
180 }
181 },
182
183 /**
184 * Public initializes a canvas element so that it can be used as canvas
185 * element from now on. This is called automatically before the page is
186 * loaded but if you are creating elements using createElement you need to
187 * make sure this is called on the element.
188 * @param {HTMLElement} el The canvas element to initialize.
189 * @return {HTMLElement} the element that was created.
190 */
191 initElement: function(el) {
192 if (!el.getContext) {
193
194 el.getContext = getContext;
195
196 // Remove fallback content. There is no way to hide text nodes so we
197 // just remove all childNodes. We could hide all elements and remove
198 // text nodes but who really cares about the fallback content.
199 el.innerHTML = '';
200
201 // do not use inline function because that will leak memory
202 el.attachEvent('onpropertychange', onPropertyChange);
203 el.attachEvent('onresize', onResize);
204
205 var attrs = el.attributes;
206 if (attrs.width && attrs.width.specified) {
207 // TODO: use runtimeStyle and coordsize
208 // el.getContext().setWidth_(attrs.width.nodeValue);
209 el.style.width = attrs.width.nodeValue + 'px';
210 } else {
211 el.width = el.clientWidth;
212 }
213 if (attrs.height && attrs.height.specified) {
214 // TODO: use runtimeStyle and coordsize
215 // el.getContext().setHeight_(attrs.height.nodeValue);
216 el.style.height = attrs.height.nodeValue + 'px';
217 } else {
218 el.height = el.clientHeight;
219 }
220 //el.getContext().setCoordsize_()
221 }
222 return el;
223 }
224 };
225
226 function onPropertyChange(e) {
227 var el = e.srcElement;
228
229 switch (e.propertyName) {
230 case 'width':
231 el.style.width = el.attributes.width.nodeValue + 'px';
232 el.getContext().clearRect();
233 break;
234 case 'height':
235 el.style.height = el.attributes.height.nodeValue + 'px';
236 el.getContext().clearRect();
237 break;
238 }
239 }
240
241 function onResize(e) {
242 var el = e.srcElement;
243 if (el.firstChild) {
244 el.firstChild.style.width = el.clientWidth + 'px';
245 el.firstChild.style.height = el.clientHeight + 'px';
246 }
247 }
248
249 G_vmlCanvasManager_.init();
250
251 // precompute "00" to "FF"
252 var dec2hex = [];
253 for (var i = 0; i < 16; i++) {
254 for (var j = 0; j < 16; j++) {
255 dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
256 }
257 }
258
259 function createMatrixIdentity() {
260 return [
261 [1, 0, 0],
262 [0, 1, 0],
263 [0, 0, 1]
264 ];
265 }
266
267 function matrixMultiply(m1, m2) {
268 var result = createMatrixIdentity();
269
270 for (var x = 0; x < 3; x++) {
271 for (var y = 0; y < 3; y++) {
272 var sum = 0;
273
274 for (var z = 0; z < 3; z++) {
275 sum += m1[x][z] * m2[z][y];
276 }
277
278 result[x][y] = sum;
279 }
280 }
281 return result;
282 }
283
284 function copyState(o1, o2) {
285 o2.fillStyle = o1.fillStyle;
286 o2.lineCap = o1.lineCap;
287 o2.lineJoin = o1.lineJoin;
288 o2.lineWidth = o1.lineWidth;
289 o2.miterLimit = o1.miterLimit;
290 o2.shadowBlur = o1.shadowBlur;
291 o2.shadowColor = o1.shadowColor;
292 o2.shadowOffsetX = o1.shadowOffsetX;
293 o2.shadowOffsetY = o1.shadowOffsetY;
294 o2.strokeStyle = o1.strokeStyle;
295 o2.globalAlpha = o1.globalAlpha;
296 o2.arcScaleX_ = o1.arcScaleX_;
297 o2.arcScaleY_ = o1.arcScaleY_;
298 o2.lineScale_ = o1.lineScale_;
299 }
300
301 function processStyle(styleString) {
302 var str, alpha = 1;
303
304 styleString = String(styleString);
305 if (styleString.substring(0, 3) == 'rgb') {
306 var start = styleString.indexOf('(', 3);
307 var end = styleString.indexOf(')', start + 1);
308 var guts = styleString.substring(start + 1, end).split(',');
309
310 str = '#';
311 for (var i = 0; i < 3; i++) {
312 str += dec2hex[Number(guts[i])];
313 }
314
315 if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
316 alpha = guts[3];
317 }
318 } else {
319 str = styleString;
320 }
321
322 return {color: str, alpha: alpha};
323 }
324
325 function processLineCap(lineCap) {
326 switch (lineCap) {
327 case 'butt':
328 return 'flat';
329 case 'round':
330 return 'round';
331 case 'square':
332 default:
333 return 'square';
334 }
335 }
336
337 /**
338 * This class implements CanvasRenderingContext2D interface as described by
339 * the WHATWG.
340 * @param {HTMLElement} surfaceElement The element that the 2D context should
341 * be associated with
342 */
343 function CanvasRenderingContext2D_(surfaceElement) {
344 this.m_ = createMatrixIdentity();
345
346 this.mStack_ = [];
347 this.aStack_ = [];
348 this.currentPath_ = [];
349
350 // Canvas context properties
351 this.strokeStyle = '#000';
352 this.fillStyle = '#000';
353
354 this.lineWidth = 1;
355 this.lineJoin = 'miter';
356 this.lineCap = 'butt';
357 this.miterLimit = Z * 1;
358 this.globalAlpha = 1;
359 this.canvas = surfaceElement;
360
361 var el = surfaceElement.ownerDocument.createElement('div');
362 el.style.width = surfaceElement.clientWidth + 'px';
363 el.style.height = surfaceElement.clientHeight + 'px';
364 el.style.overflow = 'hidden';
365 el.style.position = 'absolute';
366 surfaceElement.appendChild(el);
367
368 this.element_ = el;
369 this.arcScaleX_ = 1;
370 this.arcScaleY_ = 1;
371 this.lineScale_ = 1;
372 }
373
374 var contextPrototype = CanvasRenderingContext2D_.prototype;
375 contextPrototype.clearRect = function() {
376 this.element_.innerHTML = '';
377 };
378
379 contextPrototype.beginPath = function() {
380 // TODO: Branch current matrix so that save/restore has no effect
381 // as per safari docs.
382 this.currentPath_ = [];
383 };
384
385 contextPrototype.moveTo = function(aX, aY) {
386 var p = this.getCoords_(aX, aY);
387 this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
388 this.currentX_ = p.x;
389 this.currentY_ = p.y;
390 };
391
392 contextPrototype.lineTo = function(aX, aY) {
393 var p = this.getCoords_(aX, aY);
394 this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
395
396 this.currentX_ = p.x;
397 this.currentY_ = p.y;
398 };
399
400 contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
401 aCP2x, aCP2y,
402 aX, aY) {
403 var p = this.getCoords_(aX, aY);
404 var cp1 = this.getCoords_(aCP1x, aCP1y);
405 var cp2 = this.getCoords_(aCP2x, aCP2y);
406 bezierCurveTo(this, cp1, cp2, p);
407 };
408
409 // Helper function that takes the already fixed cordinates.
410 function bezierCurveTo(self, cp1, cp2, p) {
411 self.currentPath_.push({
412 type: 'bezierCurveTo',
413 cp1x: cp1.x,
414 cp1y: cp1.y,
415 cp2x: cp2.x,
416 cp2y: cp2.y,
417 x: p.x,
418 y: p.y
419 });
420 self.currentX_ = p.x;
421 self.currentY_ = p.y;
422 }
423
424 contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
425 // the following is lifted almost directly from
426 // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
427
428 var cp = this.getCoords_(aCPx, aCPy);
429 var p = this.getCoords_(aX, aY);
430
431 var cp1 = {
432 x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
433 y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
434 };
435 var cp2 = {
436 x: cp1.x + (p.x - this.currentX_) / 3.0,
437 y: cp1.y + (p.y - this.currentY_) / 3.0
438 };
439
440 bezierCurveTo(this, cp1, cp2, p);
441 };
442
443 contextPrototype.arc = function(aX, aY, aRadius,
444 aStartAngle, aEndAngle, aClockwise) {
445 aRadius *= Z;
446 var arcType = aClockwise ? 'at' : 'wa';
447
448 var xStart = aX + mc(aStartAngle) * aRadius - Z2;
449 var yStart = aY + ms(aStartAngle) * aRadius - Z2;
450
451 var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
452 var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
453
454 // IE won't render arches drawn counter clockwise if xStart == xEnd.
455 if (xStart == xEnd && !aClockwise) {
456 xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
457 // that can be represented in binary
458 }
459
460 var p = this.getCoords_(aX, aY);
461 var pStart = this.getCoords_(xStart, yStart);
462 var pEnd = this.getCoords_(xEnd, yEnd);
463
464 this.currentPath_.push({type: arcType,
465 x: p.x,
466 y: p.y,
467 radius: aRadius,
468 xStart: pStart.x,
469 yStart: pStart.y,
470 xEnd: pEnd.x,
471 yEnd: pEnd.y});
472
473 };
474
475 contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
476 this.moveTo(aX, aY);
477 this.lineTo(aX + aWidth, aY);
478 this.lineTo(aX + aWidth, aY + aHeight);
479 this.lineTo(aX, aY + aHeight);
480 this.closePath();
481 };
482
483 contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
484 var oldPath = this.currentPath_;
485 this.beginPath();
486
487 this.moveTo(aX, aY);
488 this.lineTo(aX + aWidth, aY);
489 this.lineTo(aX + aWidth, aY + aHeight);
490 this.lineTo(aX, aY + aHeight);
491 this.closePath();
492 this.stroke();
493
494 this.currentPath_ = oldPath;
495 };
496
497 contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
498 var oldPath = this.currentPath_;
499 this.beginPath();
500
501 this.moveTo(aX, aY);
502 this.lineTo(aX + aWidth, aY);
503 this.lineTo(aX + aWidth, aY + aHeight);
504 this.lineTo(aX, aY + aHeight);
505 this.closePath();
506 this.fill();
507
508 this.currentPath_ = oldPath;
509 };
510
511 contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
512 var gradient = new CanvasGradient_('gradient');
513 gradient.x0_ = aX0;
514 gradient.y0_ = aY0;
515 gradient.x1_ = aX1;
516 gradient.y1_ = aY1;
517 return gradient;
518 };
519
520 contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
521 aX1, aY1, aR1) {
522 var gradient = new CanvasGradient_('gradientradial');
523 gradient.x0_ = aX0;
524 gradient.y0_ = aY0;
525 gradient.r0_ = aR0;
526 gradient.x1_ = aX1;
527 gradient.y1_ = aY1;
528 gradient.r1_ = aR1;
529 return gradient;
530 };
531
532 contextPrototype.drawImage = function(image, var_args) {
533 var dx, dy, dw, dh, sx, sy, sw, sh;
534
535 // to find the original width we overide the width and height
536 var oldRuntimeWidth = image.runtimeStyle.width;
537 var oldRuntimeHeight = image.runtimeStyle.height;
538 image.runtimeStyle.width = 'auto';
539 image.runtimeStyle.height = 'auto';
540
541 // get the original size
542 var w = image.width;
543 var h = image.height;
544
545 // and remove overides
546 image.runtimeStyle.width = oldRuntimeWidth;
547 image.runtimeStyle.height = oldRuntimeHeight;
548
549 if (arguments.length == 3) {
550 dx = arguments[1];
551 dy = arguments[2];
552 sx = sy = 0;
553 sw = dw = w;
554 sh = dh = h;
555 } else if (arguments.length == 5) {
556 dx = arguments[1];
557 dy = arguments[2];
558 dw = arguments[3];
559 dh = arguments[4];
560 sx = sy = 0;
561 sw = w;
562 sh = h;
563 } else if (arguments.length == 9) {
564 sx = arguments[1];
565 sy = arguments[2];
566 sw = arguments[3];
567 sh = arguments[4];
568 dx = arguments[5];
569 dy = arguments[6];
570 dw = arguments[7];
571 dh = arguments[8];
572 } else {
573 throw Error('Invalid number of arguments');
574 }
575
576 var d = this.getCoords_(dx, dy);
577
578 var w2 = sw / 2;
579 var h2 = sh / 2;
580
581 var vmlStr = [];
582
583 var W = 10;
584 var H = 10;
585
586 // For some reason that I've now forgotten, using divs didn't work
587 vmlStr.push(' <g_vml_:group',
588 ' coordsize="', Z * W, ',', Z * H, '"',
589 ' coordorigin="0,0"' ,
590 ' style="width:', W, 'px;height:', H, 'px;position:absolute;');
591
592 // If filters are necessary (rotation exists), create them
593 // filters are bog-slow, so only create them if abbsolutely necessary
594 // The following check doesn't account for skews (which don't exist
595 // in the canvas spec (yet) anyway.
596
597 if (this.m_[0][0] != 1 || this.m_[0][1]) {
598 var filter = [];
599
600 // Note the 12/21 reversal
601 filter.push('M11=', this.m_[0][0], ',',
602 'M12=', this.m_[1][0], ',',
603 'M21=', this.m_[0][1], ',',
604 'M22=', this.m_[1][1], ',',
605 'Dx=', mr(d.x / Z), ',',
606 'Dy=', mr(d.y / Z), '');
607
608 // Bounding box calculation (need to minimize displayed area so that
609 // filters don't waste time on unused pixels.
610 var max = d;
611 var c2 = this.getCoords_(dx + dw, dy);
612 var c3 = this.getCoords_(dx, dy + dh);
613 var c4 = this.getCoords_(dx + dw, dy + dh);
614
615 max.x = m.max(max.x, c2.x, c3.x, c4.x);
616 max.y = m.max(max.y, c2.y, c3.y, c4.y);
617
618 vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
619 'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
620 filter.join(''), ", sizingmethod='clip');")
621 } else {
622 vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
623 }
624
625 vmlStr.push(' ">' ,
626 '<g_vml_:image src="', image.src, '"',
627 ' style="width:', Z * dw, 'px;',
628 ' height:', Z * dh, 'px;"',
629 ' cropleft="', sx / w, '"',
630 ' croptop="', sy / h, '"',
631 ' cropright="', (w - sx - sw) / w, '"',
632 ' cropbottom="', (h - sy - sh) / h, '"',
633 ' />',
634 '</g_vml_:group>');
635
636 this.element_.insertAdjacentHTML('BeforeEnd',
637 vmlStr.join(''));
638 };
639
640 contextPrototype.stroke = function(aFill) {
641 var lineStr = [];
642 var lineOpen = false;
643 var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
644 var color = a.color;
645 var opacity = a.alpha * this.globalAlpha;
646
647 var W = 10;
648 var H = 10;
649
650 lineStr.push('<g_vml_:shape',
651 ' filled="', !!aFill, '"',
652 ' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
653 ' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
654 ' stroked="', !aFill, '"',
655 ' path="');
656
657 var newSeq = false;
658 var min = {x: null, y: null};
659 var max = {x: null, y: null};
660
661 for (var i = 0; i < this.currentPath_.length; i++) {
662 var p = this.currentPath_[i];
663 var c;
664
665 switch (p.type) {
666 case 'moveTo':
667 c = p;
668 lineStr.push(' m ', mr(p.x), ',', mr(p.y));
669 break;
670 case 'lineTo':
671 lineStr.push(' l ', mr(p.x), ',', mr(p.y));
672 break;
673 case 'close':
674 lineStr.push(' x ');
675 p = null;
676 break;
677 case 'bezierCurveTo':
678 lineStr.push(' c ',
679 mr(p.cp1x), ',', mr(p.cp1y), ',',
680 mr(p.cp2x), ',', mr(p.cp2y), ',',
681 mr(p.x), ',', mr(p.y));
682 break;
683 case 'at':
684 case 'wa':
685 lineStr.push(' ', p.type, ' ',
686 mr(p.x - this.arcScaleX_ * p.radius), ',',
687 mr(p.y - this.arcScaleY_ * p.radius), ' ',
688 mr(p.x + this.arcScaleX_ * p.radius), ',',
689 mr(p.y + this.arcScaleY_ * p.radius), ' ',
690 mr(p.xStart), ',', mr(p.yStart), ' ',
691 mr(p.xEnd), ',', mr(p.yEnd));
692 break;
693 }
694
695
696 // TODO: Following is broken for curves due to
697 // move to proper paths.
698
699 // Figure out dimensions so we can do gradient fills
700 // properly
701 if (p) {
702 if (min.x == null || p.x < min.x) {
703 min.x = p.x;
704 }
705 if (max.x == null || p.x > max.x) {
706 max.x = p.x;
707 }
708 if (min.y == null || p.y < min.y) {
709 min.y = p.y;
710 }
711 if (max.y == null || p.y > max.y) {
712 max.y = p.y;
713 }
714 }
715 }
716 lineStr.push(' ">');
717
718 if (!aFill) {
719 var lineWidth = this.lineScale_ * this.lineWidth;
720
721 // VML cannot correctly render a line if the width is less than 1px.
722 // In that case, we dilute the color to make the line look thinner.
723 if (lineWidth < 1) {
724 opacity *= lineWidth;
725 }
726
727 lineStr.push(
728 '<g_vml_:stroke',
729 ' opacity="', opacity, '"',
730 ' joinstyle="', this.lineJoin, '"',
731 ' miterlimit="', this.miterLimit, '"',
732 ' endcap="', processLineCap(this.lineCap), '"',
733 ' weight="', lineWidth, 'px"',
734 ' color="', color, '" />'
735 );
736 } else if (typeof this.fillStyle == 'object') {
737 var fillStyle = this.fillStyle;
738 var angle = 0;
739 var focus = {x: 0, y: 0};
740
741 // additional offset
742 var shift = 0;
743 // scale factor for offset
744 var expansion = 1;
745
746 if (fillStyle.type_ == 'gradient') {
747 var x0 = fillStyle.x0_ / this.arcScaleX_;
748 var y0 = fillStyle.y0_ / this.arcScaleY_;
749 var x1 = fillStyle.x1_ / this.arcScaleX_;
750 var y1 = fillStyle.y1_ / this.arcScaleY_;
751 var p0 = this.getCoords_(x0, y0);
752 var p1 = this.getCoords_(x1, y1);
753 var dx = p1.x - p0.x;
754 var dy = p1.y - p0.y;
755 angle = Math.atan2(dx, dy) * 180 / Math.PI;
756
757 // The angle should be a non-negative number.
758 if (angle < 0) {
759 angle += 360;
760 }
761
762 // Very small angles produce an unexpected result because they are
763 // converted to a scientific notation string.
764 if (angle < 1e-6) {
765 angle = 0;
766 }
767 } else {
768 var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
769 var width = max.x - min.x;
770 var height = max.y - min.y;
771 focus = {
772 x: (p0.x - min.x) / width,
773 y: (p0.y - min.y) / height
774 };
775
776 width /= this.arcScaleX_ * Z;
777 height /= this.arcScaleY_ * Z;
778 var dimension = m.max(width, height);
779 shift = 2 * fillStyle.r0_ / dimension;
780 expansion = 2 * fillStyle.r1_ / dimension - shift;
781 }
782
783 // We need to sort the color stops in ascending order by offset,
784 // otherwise IE won't interpret it correctly.
785 var stops = fillStyle.colors_;
786 stops.sort(function(cs1, cs2) {
787 return cs1.offset - cs2.offset;
788 });
789
790 var length = stops.length;
791 var color1 = stops[0].color;
792 var color2 = stops[length - 1].color;
793 var opacity1 = stops[0].alpha * this.globalAlpha;
794 var opacity2 = stops[length - 1].alpha * this.globalAlpha;
795
796 var colors = [];
797 for (var i = 0; i < length; i++) {
798 var stop = stops[i];
799 colors.push(stop.offset * expansion + shift + ' ' + stop.color);
800 }
801
802 // When colors attribute is used, the meanings of opacity and o:opacity2
803 // are reversed.
804 lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
805 ' method="none" focus="100%"',
806 ' color="', color1, '"',
807 ' color2="', color2, '"',
808 ' colors="', colors.join(','), '"',
809 ' opacity="', opacity2, '"',
810 ' g_o_:opacity2="', opacity1, '"',
811 ' angle="', angle, '"',
812 ' focusposition="', focus.x, ',', focus.y, '" />');
813 } else {
814 lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
815 '" />');
816 }
817
818 lineStr.push('</g_vml_:shape>');
819
820 this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
821 };
822
823 contextPrototype.fill = function() {
824 this.stroke(true);
825 }
826
827 contextPrototype.closePath = function() {
828 this.currentPath_.push({type: 'close'});
829 };
830
831 /**
832 * @private
833 */
834 contextPrototype.getCoords_ = function(aX, aY) {
835 var m = this.m_;
836 return {
837 x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
838 y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
839 }
840 };
841
842 contextPrototype.save = function() {
843 var o = {};
844 copyState(this, o);
845 this.aStack_.push(o);
846 this.mStack_.push(this.m_);
847 this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
848 };
849
850 contextPrototype.restore = function() {
851 copyState(this.aStack_.pop(), this);
852 this.m_ = this.mStack_.pop();
853 };
854
855 function matrixIsFinite(m) {
856 for (var j = 0; j < 3; j++) {
857 for (var k = 0; k < 2; k++) {
858 if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
859 return false;
860 }
861 }
862 }
863 return true;
864 }
865
866 function setM(ctx, m, updateLineScale) {
867 if (!matrixIsFinite(m)) {
868 return;
869 }
870 ctx.m_ = m;
871
872 if (updateLineScale) {
873 // Get the line scale.
874 // Determinant of this.m_ means how much the area is enlarged by the
875 // transformation. So its square root can be used as a scale factor
876 // for width.
877 var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
878 ctx.lineScale_ = sqrt(abs(det));
879 }
880 }
881
882 contextPrototype.translate = function(aX, aY) {
883 var m1 = [
884 [1, 0, 0],
885 [0, 1, 0],
886 [aX, aY, 1]
887 ];
888
889 setM(this, matrixMultiply(m1, this.m_), false);
890 };
891
892 contextPrototype.rotate = function(aRot) {
893 var c = mc(aRot);
894 var s = ms(aRot);
895
896 var m1 = [
897 [c, s, 0],
898 [-s, c, 0],
899 [0, 0, 1]
900 ];
901
902 setM(this, matrixMultiply(m1, this.m_), false);
903 };
904
905 contextPrototype.scale = function(aX, aY) {
906 this.arcScaleX_ *= aX;
907 this.arcScaleY_ *= aY;
908 var m1 = [
909 [aX, 0, 0],
910 [0, aY, 0],
911 [0, 0, 1]
912 ];
913
914 setM(this, matrixMultiply(m1, this.m_), true);
915 };
916
917 contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
918 var m1 = [
919 [m11, m12, 0],
920 [m21, m22, 0],
921 [dx, dy, 1]
922 ];
923
924 setM(this, matrixMultiply(m1, this.m_), true);
925 };
926
927 contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
928 var m = [
929 [m11, m12, 0],
930 [m21, m22, 0],
931 [dx, dy, 1]
932 ];
933
934 setM(this, m, true);
935 };
936
937 /******** STUBS ********/
938 contextPrototype.clip = function() {
939 // TODO: Implement
940 };
941
942 contextPrototype.arcTo = function() {
943 // TODO: Implement
944 };
945
946 contextPrototype.createPattern = function() {
947 return new CanvasPattern_;
948 };
949
950 // Gradient / Pattern Stubs
951 function CanvasGradient_(aType) {
952 this.type_ = aType;
953 this.x0_ = 0;
954 this.y0_ = 0;
955 this.r0_ = 0;
956 this.x1_ = 0;
957 this.y1_ = 0;
958 this.r1_ = 0;
959 this.colors_ = [];
960 }
961
962 CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
963 aColor = processStyle(aColor);
964 this.colors_.push({offset: aOffset,
965 color: aColor.color,
966 alpha: aColor.alpha});
967 };
968
969 function CanvasPattern_() {}
970
971 // set up externs
972 G_vmlCanvasManager = G_vmlCanvasManager_;
973 CanvasRenderingContext2D = CanvasRenderingContext2D_;
974 CanvasGradient = CanvasGradient_;
975 CanvasPattern = CanvasPattern_;
976
977 })();
978
979 } // if
980 /*----------------------------------------------------------------------------\
981 | Range Class |
982 |-----------------------------------------------------------------------------|
983 | Created by Erik Arvidsson |
984 | (http://webfx.eae.net/contact.html#erik) |
985 | For WebFX (http://webfx.eae.net/) |
986 |-----------------------------------------------------------------------------|
987 | Used to model the data used when working with sliders, scrollbars and |
988 | progress bars. Based on the ideas of the javax.swing.BoundedRangeModel |
989 | interface defined by Sun for Java; http://java.sun.com/products/jfc/ |
990 | swingdoc-api-1.0.3/com/sun/java/swing/BoundedRangeModel.html |
991 |-----------------------------------------------------------------------------|
992 | Copyright (c) 2002, 2005, 2006 Erik Arvidsson |
993 |-----------------------------------------------------------------------------|
994 | Licensed under the Apache License, Version 2.0 (the "License"); you may not |
995 | use this file except in compliance with the License. You may obtain a copy |
996 | of the License at http://www.apache.org/licenses/LICENSE-2.0 |
997 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
998 | Unless required by applicable law or agreed to in writing, software |
999 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
1000 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
1001 | License for the specific language governing permissions and limitations |
1002 | under the License. |
1003 |-----------------------------------------------------------------------------|
1004 | 2002-10-14 | Original version released |
1005 | 2005-10-27 | Use Math.round instead of Math.floor |
1006 | 2006-05-28 | Changed license to Apache Software License 2.0. |
1007 |-----------------------------------------------------------------------------|
1008 | Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
1009 \----------------------------------------------------------------------------*/
1010
1011
1012 function Range() {
1013 this._value = 0;
1014 this._minimum = 0;
1015 this._maximum = 100;
1016 this._extent = 0;
1017
1018 this._isChanging = false;
1019 }
1020
1021 Range.prototype.setValue = function (value) {
1022 value = Math.round(parseFloat(value));
1023 if (isNaN(value)) return;
1024 if (this._value != value) {
1025 if (value + this._extent > this._maximum)
1026 this._value = this._maximum - this._extent;
1027 else if (value < this._minimum)
1028 this._value = this._minimum;
1029 else
1030 this._value = value;
1031 if (!this._isChanging && typeof this.onchange == "function")
1032 this.onchange();
1033 }
1034 };
1035
1036 Range.prototype.getValue = function () {
1037 return this._value;
1038 };
1039
1040 Range.prototype.setExtent = function (extent) {
1041 if (this._extent != extent) {
1042 if (extent < 0)
1043 this._extent = 0;
1044 else if (this._value + extent > this._maximum)
1045 this._extent = this._maximum - this._value;
1046 else
1047 this._extent = extent;
1048 if (!this._isChanging && typeof this.onchange == "function")
1049 this.onchange();
1050 }
1051 };
1052
1053 Range.prototype.getExtent = function () {
1054 return this._extent;
1055 };
1056
1057 Range.prototype.setMinimum = function (minimum) {
1058 if (this._minimum != minimum) {
1059 var oldIsChanging = this._isChanging;
1060 this._isChanging = true;
1061
1062 this._minimum = minimum;
1063
1064 if (minimum > this._value)
1065 this.setValue(minimum);
1066 if (minimum > this._maximum) {
1067 this._extent = 0;
1068 this.setMaximum(minimum);
1069 this.setValue(minimum)
1070 }
1071 if (minimum + this._extent > this._maximum)
1072 this._extent = this._maximum - this._minimum;
1073
1074 this._isChanging = oldIsChanging;
1075 if (!this._isChanging && typeof this.onchange == "function")
1076 this.onchange();
1077 }
1078 };
1079
1080 Range.prototype.getMinimum = function () {
1081 return this._minimum;
1082 };
1083
1084 Range.prototype.setMaximum = function (maximum) {
1085 if (this._maximum != maximum) {
1086 var oldIsChanging = this._isChanging;
1087 this._isChanging = true;
1088
1089 this._maximum = maximum;
1090
1091 if (maximum < this._value)
1092 this.setValue(maximum - this._extent);
1093 if (maximum < this._minimum) {
1094 this._extent = 0;
1095 this.setMinimum(maximum);
1096 this.setValue(this._maximum);
1097 }
1098 if (maximum < this._minimum + this._extent)
1099 this._extent = this._maximum - this._minimum;
1100 if (maximum < this._value + this._extent)
1101 this._extent = this._maximum - this._value;
1102
1103 this._isChanging = oldIsChanging;
1104 if (!this._isChanging && typeof this.onchange == "function")
1105 this.onchange();
1106 }
1107 };
1108
1109 Range.prototype.getMaximum = function () {
1110 return this._maximum;
1111 };
1112 /*----------------------------------------------------------------------------\
1113 | Slider 1.02 |
1114 |-----------------------------------------------------------------------------|
1115 | Created by Erik Arvidsson |
1116 | (http://webfx.eae.net/contact.html#erik) |
1117 | For WebFX (http://webfx.eae.net/) |
1118 |-----------------------------------------------------------------------------|
1119 | A slider control that degrades to an input control for non supported |
1120 | browsers. |
1121 |-----------------------------------------------------------------------------|
1122 | Copyright (c) 2002, 2003, 2006 Erik Arvidsson |
1123 |-----------------------------------------------------------------------------|
1124 | Licensed under the Apache License, Version 2.0 (the "License"); you may not |
1125 | use this file except in compliance with the License. You may obtain a copy |
1126 | of the License at http://www.apache.org/licenses/LICENSE-2.0 |
1127 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1128 | Unless required by applicable law or agreed to in writing, software |
1129 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
1130 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
1131 | License for the specific language governing permissions and limitations |
1132 | under the License. |
1133 |-----------------------------------------------------------------------------|
1134 | Dependencies: timer.js - an OO abstraction of timers |
1135 | range.js - provides the data model for the slider |
1136 | winclassic.css or any other css file describing the look |
1137 |-----------------------------------------------------------------------------|
1138 | 2002-10-14 | Original version released |
1139 | 2003-03-27 | Added a test in the constructor for missing oElement arg |
1140 | 2003-11-27 | Only use mousewheel when focused |
1141 | 2006-05-28 | Changed license to Apache Software License 2.0. |
1142 |-----------------------------------------------------------------------------|
1143 | Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
1144 \----------------------------------------------------------------------------*/
1145
1146 Slider.isSupported = typeof document.createElement != "undefined" &&
1147 typeof document.documentElement != "undefined" &&
1148 typeof document.documentElement.offsetWidth == "number";
1149
1150
1151 function Slider(oElement, oInput, sOrientation) {
1152 if (!oElement) return;
1153 this._orientation = sOrientation || "horizontal";
1154 this._range = new Range();
1155 this._range.setExtent(0);
1156 this._blockIncrement = 10;
1157 this._unitIncrement = 1;
1158 this._timer = new Timer(100);
1159
1160
1161 if (Slider.isSupported && oElement) {
1162
1163 this.document = oElement.ownerDocument || oElement.document;
1164
1165 this.element = oElement;
1166 this.element.slider = this;
1167 this.element.unselectable = "on";
1168
1169 // add class name tag to class name
1170 this.element.className = this._orientation + " " + this.classNameTag + " " + this.element.className;
1171
1172 // create line
1173 this.line = this.document.createElement("DIV");
1174 this.line.className = "line";
1175 this.line.unselectable = "on";
1176 this.line.appendChild(this.document.createElement("DIV"));
1177 this.element.appendChild(this.line);
1178
1179 // create handle
1180 this.handle = this.document.createElement("DIV");
1181 this.handle.className = "handle";
1182 this.handle.unselectable = "on";
1183 this.handle.appendChild(this.document.createElement("DIV"));
1184 this.handle.firstChild.appendChild(
1185 this.document.createTextNode(String.fromCharCode(160)));
1186 this.element.appendChild(this.handle);
1187 }
1188
1189 this.input = oInput;
1190
1191 // events
1192 var oThis = this;
1193 this._range.onchange = function () {
1194 oThis.recalculate();
1195 if (typeof oThis.onchange == "function")
1196 oThis.onchange();
1197 };
1198
1199 if (Slider.isSupported && oElement) {
1200 this.element.onfocus = Slider.eventHandlers.onfocus;
1201 this.element.onblur = Slider.eventHandlers.onblur;
1202 this.element.onmousedown = Slider.eventHandlers.onmousedown;
1203 this.element.onmouseover = Slider.eventHandlers.onmouseover;
1204 this.element.onmouseout = Slider.eventHandlers.onmouseout;
1205 this.element.onkeydown = Slider.eventHandlers.onkeydown;
1206 this.element.onkeypress = Slider.eventHandlers.onkeypress;
1207 this.element.onmousewheel = Slider.eventHandlers.onmousewheel;
1208 this.handle.onselectstart =
1209 this.element.onselectstart = function () { return false; };
1210
1211 this._timer.ontimer = function () {
1212 oThis.ontimer();
1213 };
1214
1215 // extra recalculate for ie
1216 window.setTimeout(function() {
1217 oThis.recalculate();
1218 }, 1);
1219 }
1220 else {
1221 this.input.onchange = function (e) {
1222 oThis.setValue(oThis.input.value);
1223 };
1224 }
1225 }
1226
1227 Slider.eventHandlers = {
1228
1229 // helpers to make events a bit easier
1230 getEvent: function (e, el) {
1231 if (!e) {
1232 if (el)
1233 e = el.document.parentWindow.event;
1234 else
1235 e = window.event;
1236 }
1237 if (!e.srcElement) {
1238 var el = e.target;
1239 while (el != null && el.nodeType != 1)
1240 el = el.parentNode;
1241 e.srcElement = el;
1242 }
1243 if (typeof e.offsetX == "undefined") {
1244 e.offsetX = e.layerX;
1245 e.offsetY = e.layerY;
1246 }
1247
1248 return e;
1249 },
1250
1251 getDocument: function (e) {
1252 if (e.target)
1253 return e.target.ownerDocument;
1254 return e.srcElement.document;
1255 },
1256
1257 getSlider: function (e) {
1258 var el = e.target || e.srcElement;
1259 while (el != null && el.slider == null) {
1260 el = el.parentNode;
1261 }
1262 if (el)
1263 return el.slider;
1264 return null;
1265 },
1266
1267 getLine: function (e) {
1268 var el = e.target || e.srcElement;
1269 while (el != null && el.className != "line") {
1270 el = el.parentNode;
1271 }
1272 return el;
1273 },
1274
1275 getHandle: function (e) {
1276 var el = e.target || e.srcElement;
1277 var re = /handle/;
1278 while (el != null && !re.test(el.className)) {
1279 el = el.parentNode;
1280 }
1281 return el;
1282 },
1283 // end helpers
1284
1285 onfocus: function (e) {
1286 var s = this.slider;
1287 s._focused = true;
1288 s.handle.className = "handle hover";
1289 },
1290
1291 onblur: function (e) {
1292 var s = this.slider
1293 s._focused = false;
1294 s.handle.className = "handle";
1295 },
1296
1297 onmouseover: function (e) {
1298 e = Slider.eventHandlers.getEvent(e, this);
1299 var s = this.slider;
1300 if (e.srcElement == s.handle)
1301 s.handle.className = "handle hover";
1302 },
1303
1304 onmouseout: function (e) {
1305 e = Slider.eventHandlers.getEvent(e, this);
1306 var s = this.slider;
1307 if (e.srcElement == s.handle && !s._focused)
1308 s.handle.className = "handle";
1309 },
1310
1311 onmousedown: function (e) {
1312 e = Slider.eventHandlers.getEvent(e, this);
1313 var s = this.slider;
1314 if (s.element.focus)
1315 s.element.focus();
1316
1317 Slider._currentInstance = s;
1318 var doc = s.document;
1319
1320 if (doc.addEventListener) {
1321 doc.addEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
1322 doc.addEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
1323 }
1324 else if (doc.attachEvent) {
1325 doc.attachEvent("onmousemove", Slider.eventHandlers.onmousemove);
1326 doc.attachEvent("onmouseup", Slider.eventHandlers.onmouseup);
1327 doc.attachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
1328 s.element.setCapture();
1329 }
1330
1331 if (Slider.eventHandlers.getHandle(e)) { // start drag
1332 Slider._sliderDragData = {
1333 screenX: e.screenX,
1334 screenY: e.screenY,
1335 dx: e.screenX - s.handle.offsetLeft,
1336 dy: e.screenY - s.handle.offsetTop,
1337 startValue: s.getValue(),
1338 slider: s
1339 };
1340 }
1341 else {
1342 return;
1343 var lineEl = Slider.eventHandlers.getLine(e);
1344 s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
1345 s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
1346 s._increasing = null;
1347 s.ontimer();
1348 }
1349 },
1350
1351 onmousemove: function (e) {
1352 e = Slider.eventHandlers.getEvent(e, this);
1353
1354 if (Slider._sliderDragData) { // drag
1355 var s = Slider._sliderDragData.slider;
1356
1357 var boundSize = s.getMaximum() - s.getMinimum();
1358 var size, pos, reset;
1359
1360 if (s._orientation == "horizontal") {
1361 size = s.element.offsetWidth - s.handle.offsetWidth;
1362 pos = e.screenX - Slider._sliderDragData.dx;
1363 reset = Math.abs(e.screenY - Slider._sliderDragData.screenY) > 100;
1364 }
1365 else {
1366 size = s.element.offsetHeight - s.handle.offsetHeight;
1367 pos = s.element.offsetHeight - s.handle.offsetHeight -
1368 (e.screenY - Slider._sliderDragData.dy);
1369 reset = Math.abs(e.screenX - Slider._sliderDragData.screenX) > 100;
1370 }
1371 s.setValue(reset ? Slider._sliderDragData.startValue :
1372 s.getMinimum() + boundSize * pos / size);
1373 return false;
1374 }
1375 else {
1376 return;
1377 var s = Slider._currentInstance;
1378 if (s != null) {
1379 var lineEl = Slider.eventHandlers.getLine(e);
1380 s._mouseX = e.offsetX + (lineEl ? s.line.offsetLeft : 0);
1381 s._mouseY = e.offsetY + (lineEl ? s.line.offsetTop : 0);
1382 }
1383 }
1384
1385 },
1386
1387 onmouseup: function (e) {
1388 e = Slider.eventHandlers.getEvent(e, this);
1389 var s = Slider._currentInstance;
1390 var doc = s.document;
1391 if (doc.removeEventListener) {
1392 doc.removeEventListener("mousemove", Slider.eventHandlers.onmousemove, true);
1393 doc.removeEventListener("mouseup", Slider.eventHandlers.onmouseup, true);
1394 }
1395 else if (doc.detachEvent) {
1396 doc.detachEvent("onmousemove", Slider.eventHandlers.onmousemove);
1397 doc.detachEvent("onmouseup", Slider.eventHandlers.onmouseup);
1398 doc.detachEvent("onlosecapture", Slider.eventHandlers.onmouseup);
1399 s.element.releaseCapture();
1400 }
1401
1402 if (Slider._sliderDragData) { // end drag
1403 Slider._sliderDragData = null;
1404 }
1405 else {
1406 return;
1407 s._timer.stop();
1408 s._increasing = null;
1409 }
1410 Slider._currentInstance = null;
1411 },
1412
1413 onkeydown: function (e) {
1414 return;
1415 e = Slider.eventHandlers.getEvent(e, this);
1416 //var s = Slider.eventHandlers.getSlider(e);
1417 var s = this.slider;
1418 var kc = e.keyCode;
1419 switch (kc) {
1420 case 33: // page up
1421 s.setValue(s.getValue() + s.getBlockIncrement());
1422 break;
1423 case 34: // page down
1424 s.setValue(s.getValue() - s.getBlockIncrement());
1425 break;
1426 case 35: // end
1427 s.setValue(s.getOrientation() == "horizontal" ?
1428 s.getMaximum() :
1429 s.getMinimum());
1430 break;
1431 case 36: // home
1432 s.setValue(s.getOrientation() == "horizontal" ?
1433 s.getMinimum() :
1434 s.getMaximum());
1435 break;
1436 case 38: // up
1437 case 39: // right
1438 s.setValue(s.getValue() + s.getUnitIncrement());
1439 break;
1440
1441 case 37: // left
1442 case 40: // down
1443 s.setValue(s.getValue() - s.getUnitIncrement());
1444 break;
1445 }
1446
1447 if (kc >= 33 && kc <= 40) {
1448 return false;
1449 }
1450 },
1451
1452 onkeypress: function (e) {
1453 return;
1454 e = Slider.eventHandlers.getEvent(e, this);
1455 var kc = e.keyCode;
1456 if (kc >= 33 && kc <= 40) {
1457 return false;
1458 }
1459 },
1460
1461 onmousewheel: function (e) {
1462 return;
1463 e = Slider.eventHandlers.getEvent(e, this);
1464 var s = this.slider;
1465 if (s._focused) {
1466 s.setValue(s.getValue() + e.wheelDelta / 120 * s.getUnitIncrement());
1467 // windows inverts this on horizontal sliders. That does not
1468 // make sense to me
1469 return false;
1470 }
1471 }
1472 };
1473
1474
1475
1476 Slider.prototype.classNameTag = "dynamic-slider-control",
1477
1478 Slider.prototype.setValue = function (v) {
1479 this._range.setValue(v);
1480 this.input.value = this.getValue();
1481 };
1482
1483 Slider.prototype.getValue = function () {
1484 return this._range.getValue();
1485 };
1486
1487 Slider.prototype.setMinimum = function (v) {
1488 this._range.setMinimum(v);
1489 this.input.value = this.getValue();
1490 };
1491
1492 Slider.prototype.getMinimum = function () {
1493 return this._range.getMinimum();
1494 };
1495
1496 Slider.prototype.setMaximum = function (v) {
1497 this._range.setMaximum(v);
1498 this.input.value = this.getValue();
1499 };
1500
1501 Slider.prototype.getMaximum = function () {
1502 return this._range.getMaximum();
1503 };
1504
1505 Slider.prototype.setUnitIncrement = function (v) {
1506 this._unitIncrement = v;
1507 };
1508
1509 Slider.prototype.getUnitIncrement = function () {
1510 return this._unitIncrement;
1511 };
1512
1513 Slider.prototype.setBlockIncrement = function (v) {
1514 this._blockIncrement = v;
1515 };
1516
1517 Slider.prototype.getBlockIncrement = function () {
1518 return this._blockIncrement;
1519 };
1520
1521 Slider.prototype.getOrientation = function () {
1522 return this._orientation;
1523 };
1524
1525 Slider.prototype.setOrientation = function (sOrientation) {
1526 if (sOrientation != this._orientation) {
1527 if (Slider.isSupported && this.element) {
1528 // add class name tag to class name
1529 this.element.className = this.element.className.replace(this._orientation,
1530 sOrientation);
1531 }
1532 this._orientation = sOrientation;
1533 this.recalculate();
1534
1535 }
1536 };
1537
1538 Slider.prototype.recalculate = function() {
1539 if (!Slider.isSupported || !this.element) return;
1540
1541 var w = this.element.offsetWidth;
1542 var h = this.element.offsetHeight;
1543 var hw = this.handle.offsetWidth;
1544 var hh = this.handle.offsetHeight;
1545 var lw = this.line.offsetWidth;
1546 var lh = this.line.offsetHeight;
1547
1548 // this assumes a border-box layout
1549
1550 if (this._orientation == "horizontal") {
1551 this.handle.style.left = (w - hw) * (this.getValue() - this.getMinimum()) /
1552 (this.getMaximum() - this.getMinimum()) + "px";
1553 this.handle.style.top = (h - hh) / 2 + "px";
1554
1555 this.line.style.top = (h - lh) / 2 + "px";
1556 this.line.style.left = hw / 2 + "px";
1557 //this.line.style.right = hw / 2 + "px";
1558 this.line.style.width = Math.max(0, w - hw - 2)+ "px";
1559 this.line.firstChild.style.width = Math.max(0, w - hw - 4)+ "px";
1560 }
1561 else {
1562 this.handle.style.left = (w - hw) / 2 + "px";
1563 this.handle.style.top = h - hh - (h - hh) * (this.getValue() - this.getMinimum()) /
1564 (this.getMaximum() - this.getMinimum()) + "px";
1565
1566 this.line.style.left = (w - lw) / 2 + "px";
1567 this.line.style.top = hh / 2 + "px";
1568 this.line.style.height = Math.max(0, h - hh - 2) + "px"; //hard coded border width
1569 //this.line.style.bottom = hh / 2 + "px";
1570 this.line.firstChild.style.height = Math.max(0, h - hh - 4) + "px"; //hard coded border width
1571 }
1572 };
1573
1574 Slider.prototype.ontimer = function () {
1575 var hw = this.handle.offsetWidth;
1576 var hh = this.handle.offsetHeight;
1577 var hl = this.handle.offsetLeft;
1578 var ht = this.handle.offsetTop;
1579
1580 if (this._orientation == "horizontal") {
1581 if (this._mouseX > hl + hw &&
1582 (this._increasing == null || this._increasing)) {
1583 this.setValue(this.getValue() + this.getBlockIncrement());
1584 this._increasing = true;
1585 }
1586 else if (this._mouseX < hl &&
1587 (this._increasing == null || !this._increasing)) {
1588 this.setValue(this.getValue() - this.getBlockIncrement());
1589 this._increasing = false;
1590 }
1591 }
1592 else {
1593 if (this._mouseY > ht + hh &&
1594 (this._increasing == null || !this._increasing)) {
1595 this.setValue(this.getValue() - this.getBlockIncrement());
1596 this._increasing = false;
1597 }
1598 else if (this._mouseY < ht &&
1599 (this._increasing == null || this._increasing)) {
1600 this.setValue(this.getValue() + this.getBlockIncrement());
1601 this._increasing = true;
1602 }
1603 }
1604
1605 this._timer.start();
1606 };
1607 /*----------------------------------------------------------------------------\
1608 | Timer Class |
1609 |-----------------------------------------------------------------------------|
1610 | Created by Erik Arvidsson |
1611 | (http://webfx.eae.net/contact.html#erik) |
1612 | For WebFX (http://webfx.eae.net/) |
1613 |-----------------------------------------------------------------------------|
1614 | Object Oriented Encapsulation of setTimeout fires ontimer when the timer |
1615 | is triggered. Does not work in IE 5.00 |
1616 |-----------------------------------------------------------------------------|
1617 | Copyright (c) 2002, 2006 Erik Arvidsson |
1618 |-----------------------------------------------------------------------------|
1619 | Licensed under the Apache License, Version 2.0 (the "License"); you may not |
1620 | use this file except in compliance with the License. You may obtain a copy |
1621 | of the License at http://www.apache.org/licenses/LICENSE-2.0 |
1622 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
1623 | Unless required by applicable law or agreed to in writing, software |
1624 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
1625 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
1626 | License for the specific language governing permissions and limitations |
1627 | under the License. |
1628 |-----------------------------------------------------------------------------|
1629 | 2002-10-14 | Original version released |
1630 | 2006-05-28 | Changed license to Apache Software License 2.0. |
1631 |-----------------------------------------------------------------------------|
1632 | Created 2002-10-14 | All changes are in the log above. | Updated 2006-05-28 |
1633 \----------------------------------------------------------------------------*/
1634
1635 function Timer(nPauseTime) {
1636 this._pauseTime = typeof nPauseTime == "undefined" ? 1000 : nPauseTime;
1637 this._timer = null;
1638 this._isStarted = false;
1639 }
1640
1641 Timer.prototype.start = function () {
1642 if (this.isStarted())
1643 this.stop();
1644 var oThis = this;
1645 this._timer = window.setTimeout(function () {
1646 if (typeof oThis.ontimer == "function")
1647 oThis.ontimer();
1648 }, this._pauseTime);
1649 this._isStarted = false;
1650 };
1651
1652 Timer.prototype.stop = function () {
1653 if (this._timer != null)
1654 window.clearTimeout(this._timer);
1655 this._isStarted = false;
1656 };
1657
1658 Timer.prototype.isStarted = function () {
1659 return this._isStarted;
1660 };
1661
1662 Timer.prototype.getPauseTime = function () {
1663 return this._pauseTime;
1664 };
1665
1666 Timer.prototype.setPauseTime = function (nPauseTime) {
1667 this._pauseTime = nPauseTime;
1668 };
1669 /*
1670
1671 OpenLayers.js -- OpenLayers Map Viewer Library
1672
1673 Copyright (c) 2006-2012 by OpenLayers Contributors
1674 Published under the 2-clause BSD license.
1675 See http://openlayers.org/dev/license.txt for the full text of the license, and http://openlayers.org/dev/authors.txt for full list of contributors.
1676
1677 Includes compressed code under the following licenses:
1678
1679 (For uncompressed versions of the code used, please see the
1680 OpenLayers Github repository: <https://github.com/openlayers/openlayers>)
1681
1682 */
1683
1684 /**
1685 * Contains XMLHttpRequest.js <http://code.google.com/p/xmlhttprequest/>
1686 * Copyright 2007 Sergey Ilinsky (http://www.ilinsky.com)
1687 *
1688 * Licensed under the Apache License, Version 2.0 (the "License");
1689 * you may not use this file except in compliance with the License.
1690 * You may obtain a copy of the License at
1691 * http://www.apache.org/licenses/LICENSE-2.0
1692 */
1693
1694 /**
1695 * OpenLayers.Util.pagePosition is based on Yahoo's getXY method, which is
1696 * Copyright (c) 2006, Yahoo! Inc.
1697 * All rights reserved.
1698 *
1699 * Redistribution and use of this software in source and binary forms, with or
1700 * without modification, are permitted provided that the following conditions
1701 * are met:
1702 *
1703 * * Redistributions of source code must retain the above copyright notice,
1704 * this list of conditions and the following disclaimer.
1705 *
1706 * * Redistributions in binary form must reproduce the above copyright notice,
1707 * this list of conditions and the following disclaimer in the documentation
1708 * and/or other materials provided with the distribution.
1709 *
1710 * * Neither the name of Yahoo! Inc. nor the names of its contributors may be
1711 * used to endorse or promote products derived from this software without
1712 * specific prior written permission of Yahoo! Inc.
1713 *
1714 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1715 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1716 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1717 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
1718 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
1719 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
1720 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
1721 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
1722 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
1723 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
1724 * POSSIBILITY OF SUCH DAMAGE.
1725 */
1726 var OpenLayers={VERSION_NUMBER:"Release 2.12",singleFile:!0,_getScriptLocation:function(){for(var a=/(^|(.*?\/))(OpenLayers[^\/]*?\.js)(\?|$)/,b=document.getElementsByTagName("script"),c,d="",e=0,f=b.length;e<f;e++)if(c=b[e].getAttribute("src"))if(c=c.match(a)){d=c[1];break}return function(){return d}}(),ImgPath:""};OpenLayers.Class=function(){var a=arguments.length,b=arguments[0],c=arguments[a-1],d="function"==typeof c.initialize?c.initialize:function(){b.prototype.initialize.apply(this,arguments)};1<a?(a=[d,b].concat(Array.prototype.slice.call(arguments).slice(1,a-1),c),OpenLayers.inherit.apply(null,a)):d.prototype=c;return d};
1727 OpenLayers.inherit=function(a,b){var c=function(){};c.prototype=b.prototype;a.prototype=new c;var d,e,c=2;for(d=arguments.length;c<d;c++)e=arguments[c],"function"===typeof e&&(e=e.prototype),OpenLayers.Util.extend(a.prototype,e)};OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.extend=function(a,b){a=a||{};if(b){for(var c in b){var d=b[c];void 0!==d&&(a[c]=d)}!("function"==typeof window.Event&&b instanceof window.Event)&&(b.hasOwnProperty&&b.hasOwnProperty("toString"))&&(a.toString=b.toString)}return a};OpenLayers.String={startsWith:function(a,b){return 0==a.indexOf(b)},contains:function(a,b){return-1!=a.indexOf(b)},trim:function(a){return a.replace(/^\s\s*/,"").replace(/\s\s*$/,"")},camelize:function(a){for(var a=a.split("-"),b=a[0],c=1,d=a.length;c<d;c++)var e=a[c],b=b+(e.charAt(0).toUpperCase()+e.substring(1));return b},format:function(a,b,c){b||(b=window);return a.replace(OpenLayers.String.tokenRegEx,function(a,e){for(var f,g=e.split(/\.+/),h=0;h<g.length;h++)0==h&&(f=b),f=f[g[h]];"function"==
1728 typeof f&&(f=c?f.apply(null,c):f());return"undefined"==typeof f?"undefined":f})},tokenRegEx:/\$\{([\w.]+?)\}/g,numberRegEx:/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/,isNumeric:function(a){return OpenLayers.String.numberRegEx.test(a)},numericIf:function(a){return OpenLayers.String.isNumeric(a)?parseFloat(a):a}};
1729 OpenLayers.Number={decimalSeparator:".",thousandsSeparator:",",limitSigDigs:function(a,b){var c=0;0<b&&(c=parseFloat(a.toPrecision(b)));return c},format:function(a,b,c,d){b="undefined"!=typeof b?b:0;c="undefined"!=typeof c?c:OpenLayers.Number.thousandsSeparator;d="undefined"!=typeof d?d:OpenLayers.Number.decimalSeparator;null!=b&&(a=parseFloat(a.toFixed(b)));var e=a.toString().split(".");1==e.length&&null==b&&(b=0);a=e[0];if(c)for(var f=/(-?[0-9]+)([0-9]{3})/;f.test(a);)a=a.replace(f,"$1"+c+"$2");
1730 0==b?b=a:(c=1<e.length?e[1]:"0",null!=b&&(c+=Array(b-c.length+1).join("0")),b=a+d+c);return b}};OpenLayers.Function={bind:function(a,b){var c=Array.prototype.slice.apply(arguments,[2]);return function(){var d=c.concat(Array.prototype.slice.apply(arguments,[0]));return a.apply(b,d)}},bindAsEventListener:function(a,b){return function(c){return a.call(b,c||window.event)}},False:function(){return!1},True:function(){return!0},Void:function(){}};
1731 OpenLayers.Array={filter:function(a,b,c){var d=[];if(Array.prototype.filter)d=a.filter(b,c);else{var e=a.length;if("function"!=typeof b)throw new TypeError;for(var f=0;f<e;f++)if(f in a){var g=a[f];b.call(c,g,f,a)&&d.push(g)}}return d}};OpenLayers.Bounds=OpenLayers.Class({left:null,bottom:null,right:null,top:null,centerLonLat:null,initialize:function(a,b,c,d){OpenLayers.Util.isArray(a)&&(d=a[3],c=a[2],b=a[1],a=a[0]);null!=a&&(this.left=OpenLayers.Util.toFloat(a));null!=b&&(this.bottom=OpenLayers.Util.toFloat(b));null!=c&&(this.right=OpenLayers.Util.toFloat(c));null!=d&&(this.top=OpenLayers.Util.toFloat(d))},clone:function(){return new OpenLayers.Bounds(this.left,this.bottom,this.right,this.top)},equals:function(a){var b=!1;null!=
1732 a&&(b=this.left==a.left&&this.right==a.right&&this.top==a.top&&this.bottom==a.bottom);return b},toString:function(){return[this.left,this.bottom,this.right,this.top].join()},toArray:function(a){return!0===a?[this.bottom,this.left,this.top,this.right]:[this.left,this.bottom,this.right,this.top]},toBBOX:function(a,b){null==a&&(a=6);var c=Math.pow(10,a),d=Math.round(this.left*c)/c,e=Math.round(this.bottom*c)/c,f=Math.round(this.right*c)/c,c=Math.round(this.top*c)/c;return!0===b?e+","+d+","+c+","+f:d+
1733 ","+e+","+f+","+c},toGeometry:function(){return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(this.left,this.bottom),new OpenLayers.Geometry.Point(this.right,this.bottom),new OpenLayers.Geometry.Point(this.right,this.top),new OpenLayers.Geometry.Point(this.left,this.top)])])},getWidth:function(){return this.right-this.left},getHeight:function(){return this.top-this.bottom},getSize:function(){return new OpenLayers.Size(this.getWidth(),this.getHeight())},
1734 getCenterPixel:function(){return new OpenLayers.Pixel((this.left+this.right)/2,(this.bottom+this.top)/2)},getCenterLonLat:function(){this.centerLonLat||(this.centerLonLat=new OpenLayers.LonLat((this.left+this.right)/2,(this.bottom+this.top)/2));return this.centerLonLat},scale:function(a,b){null==b&&(b=this.getCenterLonLat());var c,d;"OpenLayers.LonLat"==b.CLASS_NAME?(c=b.lon,d=b.lat):(c=b.x,d=b.y);return new OpenLayers.Bounds((this.left-c)*a+c,(this.bottom-d)*a+d,(this.right-c)*a+c,(this.top-d)*a+
1735 d)},add:function(a,b){if(null==a||null==b)throw new TypeError("Bounds.add cannot receive null values");return new OpenLayers.Bounds(this.left+a,this.bottom+b,this.right+a,this.top+b)},extend:function(a){var b=null;if(a){switch(a.CLASS_NAME){case "OpenLayers.LonLat":b=new OpenLayers.Bounds(a.lon,a.lat,a.lon,a.lat);break;case "OpenLayers.Geometry.Point":b=new OpenLayers.Bounds(a.x,a.y,a.x,a.y);break;case "OpenLayers.Bounds":b=a}if(b){this.centerLonLat=null;if(null==this.left||b.left<this.left)this.left=
1736 b.left;if(null==this.bottom||b.bottom<this.bottom)this.bottom=b.bottom;if(null==this.right||b.right>this.right)this.right=b.right;if(null==this.top||b.top>this.top)this.top=b.top}}},containsLonLat:function(a,b){"boolean"===typeof b&&(b={inclusive:b});var b=b||{},c=this.contains(a.lon,a.lat,b.inclusive),d=b.worldBounds;d&&!c&&(c=d.getWidth(),d=Math.round((a.lon-(d.left+d.right)/2)/c),c=this.containsLonLat({lon:a.lon-d*c,lat:a.lat},{inclusive:b.inclusive}));return c},containsPixel:function(a,b){return this.contains(a.x,
1737 a.y,b)},contains:function(a,b,c){null==c&&(c=!0);if(null==a||null==b)return!1;var a=OpenLayers.Util.toFloat(a),b=OpenLayers.Util.toFloat(b),d=!1;return d=c?a>=this.left&&a<=this.right&&b>=this.bottom&&b<=this.top:a>this.left&&a<this.right&&b>this.bottom&&b<this.top},intersectsBounds:function(a,b){"boolean"===typeof b&&(b={inclusive:b});b=b||{};if(b.worldBounds)var c=this.wrapDateLine(b.worldBounds),a=a.wrapDateLine(b.worldBounds);else c=this;null==b.inclusive&&(b.inclusive=!0);var d=!1,e=c.left==
1738 a.right||c.right==a.left||c.top==a.bottom||c.bottom==a.top;if(b.inclusive||!e)var d=a.top>=c.bottom&&a.top<=c.top||c.top>a.bottom&&c.top<a.top,e=a.left>=c.left&&a.left<=c.right||c.left>=a.left&&c.left<=a.right,f=a.right>=c.left&&a.right<=c.right||c.right>=a.left&&c.right<=a.right,d=(a.bottom>=c.bottom&&a.bottom<=c.top||c.bottom>=a.bottom&&c.bottom<=a.top||d)&&(e||f);if(b.worldBounds&&!d){var g=b.worldBounds,e=g.getWidth(),f=!g.containsBounds(c),g=!g.containsBounds(a);f&&!g?(a=a.add(-e,0),d=c.intersectsBounds(a,
1739 {inclusive:b.inclusive})):g&&!f&&(c=c.add(-e,0),d=a.intersectsBounds(c,{inclusive:b.inclusive}))}return d},containsBounds:function(a,b,c){null==b&&(b=!1);null==c&&(c=!0);var d=this.contains(a.left,a.bottom,c),e=this.contains(a.right,a.bottom,c),f=this.contains(a.left,a.top,c),a=this.contains(a.right,a.top,c);return b?d||e||f||a:d&&e&&f&&a},determineQuadrant:function(a){var b="",c=this.getCenterLonLat(),b=b+(a.lat<c.lat?"b":"t");return b+=a.lon<c.lon?"l":"r"},transform:function(a,b){this.centerLonLat=
1740 null;var c=OpenLayers.Projection.transform({x:this.left,y:this.bottom},a,b),d=OpenLayers.Projection.transform({x:this.right,y:this.bottom},a,b),e=OpenLayers.Projection.transform({x:this.left,y:this.top},a,b),f=OpenLayers.Projection.transform({x:this.right,y:this.top},a,b);this.left=Math.min(c.x,e.x);this.bottom=Math.min(c.y,d.y);this.right=Math.max(d.x,f.x);this.top=Math.max(e.y,f.y);return this},wrapDateLine:function(a,b){var b=b||{},c=b.leftTolerance||0,d=b.rightTolerance||0,e=this.clone();if(a){for(var f=
1741 a.getWidth();e.left<a.left&&e.right-d<=a.left;)e=e.add(f,0);for(;e.left+c>=a.right&&e.right>a.right;)e=e.add(-f,0);c=e.left+c;c<a.right&&(c>a.left&&e.right-d>a.right)&&(e=e.add(-f,0))}return e},CLASS_NAME:"OpenLayers.Bounds"});OpenLayers.Bounds.fromString=function(a,b){var c=a.split(",");return OpenLayers.Bounds.fromArray(c,b)};OpenLayers.Bounds.fromArray=function(a,b){return!0===b?new OpenLayers.Bounds(a[1],a[0],a[3],a[2]):new OpenLayers.Bounds(a[0],a[1],a[2],a[3])};
1742 OpenLayers.Bounds.fromSize=function(a){return new OpenLayers.Bounds(0,a.h,a.w,0)};OpenLayers.Bounds.oppositeQuadrant=function(a){var b;b=""+("t"==a.charAt(0)?"b":"t");return b+="l"==a.charAt(1)?"r":"l"};OpenLayers.Element={visible:function(a){return"none"!=OpenLayers.Util.getElement(a).style.display},toggle:function(){for(var a=0,b=arguments.length;a<b;a++){var c=OpenLayers.Util.getElement(arguments[a]),d=OpenLayers.Element.visible(c)?"none":"";c.style.display=d}},remove:function(a){a=OpenLayers.Util.getElement(a);a.parentNode.removeChild(a)},getHeight:function(a){a=OpenLayers.Util.getElement(a);return a.offsetHeight},hasClass:function(a,b){var c=a.className;return!!c&&RegExp("(^|\\s)"+b+"(\\s|$)").test(c)},
1743 addClass:function(a,b){OpenLayers.Element.hasClass(a,b)||(a.className+=(a.className?" ":"")+b);return a},removeClass:function(a,b){var c=a.className;c&&(a.className=OpenLayers.String.trim(c.replace(RegExp("(^|\\s+)"+b+"(\\s+|$)")," ")));return a},toggleClass:function(a,b){OpenLayers.Element.hasClass(a,b)?OpenLayers.Element.removeClass(a,b):OpenLayers.Element.addClass(a,b);return a},getStyle:function(a,b){var a=OpenLayers.Util.getElement(a),c=null;if(a&&a.style){c=a.style[OpenLayers.String.camelize(b)];
1744 c||(document.defaultView&&document.defaultView.getComputedStyle?c=(c=document.defaultView.getComputedStyle(a,null))?c.getPropertyValue(b):null:a.currentStyle&&(c=a.currentStyle[OpenLayers.String.camelize(b)]));var d=["left","top","right","bottom"];window.opera&&(-1!=OpenLayers.Util.indexOf(d,b)&&"static"==OpenLayers.Element.getStyle(a,"position"))&&(c="auto")}return"auto"==c?null:c}};OpenLayers.LonLat=OpenLayers.Class({lon:0,lat:0,initialize:function(a,b){OpenLayers.Util.isArray(a)&&(b=a[1],a=a[0]);this.lon=OpenLayers.Util.toFloat(a);this.lat=OpenLayers.Util.toFloat(b)},toString:function(){return"lon="+this.lon+",lat="+this.lat},toShortString:function(){return this.lon+", "+this.lat},clone:function(){return new OpenLayers.LonLat(this.lon,this.lat)},add:function(a,b){if(null==a||null==b)throw new TypeError("LonLat.add cannot receive null values");return new OpenLayers.LonLat(this.lon+
1745 OpenLayers.Util.toFloat(a),this.lat+OpenLayers.Util.toFloat(b))},equals:function(a){var b=!1;null!=a&&(b=this.lon==a.lon&&this.lat==a.lat||isNaN(this.lon)&&isNaN(this.lat)&&isNaN(a.lon)&&isNaN(a.lat));return b},transform:function(a,b){var c=OpenLayers.Projection.transform({x:this.lon,y:this.lat},a,b);this.lon=c.x;this.lat=c.y;return this},wrapDateLine:function(a){var b=this.clone();if(a){for(;b.lon<a.left;)b.lon+=a.getWidth();for(;b.lon>a.right;)b.lon-=a.getWidth()}return b},CLASS_NAME:"OpenLayers.LonLat"});
1746 OpenLayers.LonLat.fromString=function(a){a=a.split(",");return new OpenLayers.LonLat(a[0],a[1])};OpenLayers.LonLat.fromArray=function(a){var b=OpenLayers.Util.isArray(a);return new OpenLayers.LonLat(b&&a[0],b&&a[1])};OpenLayers.Pixel=OpenLayers.Class({x:0,y:0,initialize:function(a,b){this.x=parseFloat(a);this.y=parseFloat(b)},toString:function(){return"x="+this.x+",y="+this.y},clone:function(){return new OpenLayers.Pixel(this.x,this.y)},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},distanceTo:function(a){return Math.sqrt(Math.pow(this.x-a.x,2)+Math.pow(this.y-a.y,2))},add:function(a,b){if(null==a||null==b)throw new TypeError("Pixel.add cannot receive null values");
1747 return new OpenLayers.Pixel(this.x+a,this.y+b)},offset:function(a){var b=this.clone();a&&(b=this.add(a.x,a.y));return b},CLASS_NAME:"OpenLayers.Pixel"});OpenLayers.Size=OpenLayers.Class({w:0,h:0,initialize:function(a,b){this.w=parseFloat(a);this.h=parseFloat(b)},toString:function(){return"w="+this.w+",h="+this.h},clone:function(){return new OpenLayers.Size(this.w,this.h)},equals:function(a){var b=!1;null!=a&&(b=this.w==a.w&&this.h==a.h||isNaN(this.w)&&isNaN(this.h)&&isNaN(a.w)&&isNaN(a.h));return b},CLASS_NAME:"OpenLayers.Size"});OpenLayers.Console={log:function(){},debug:function(){},info:function(){},warn:function(){},error:function(){},userError:function(a){alert(a)},assert:function(){},dir:function(){},dirxml:function(){},trace:function(){},group:function(){},groupEnd:function(){},time:function(){},timeEnd:function(){},profile:function(){},profileEnd:function(){},count:function(){},CLASS_NAME:"OpenLayers.Console"};
1748 (function(){for(var a=document.getElementsByTagName("script"),b=0,c=a.length;b<c;++b)if(-1!=a[b].src.indexOf("firebug.js")&&console){OpenLayers.Util.extend(OpenLayers.Console,console);break}})();OpenLayers.Lang={code:null,defaultCode:"en",getCode:function(){OpenLayers.Lang.code||OpenLayers.Lang.setCode();return OpenLayers.Lang.code},setCode:function(a){var b;a||(a="msie"==OpenLayers.BROWSER_NAME?navigator.userLanguage:navigator.language);a=a.split("-");a[0]=a[0].toLowerCase();"object"==typeof OpenLayers.Lang[a[0]]&&(b=a[0]);if(a[1]){var c=a[0]+"-"+a[1].toUpperCase();"object"==typeof OpenLayers.Lang[c]&&(b=c)}b||(OpenLayers.Console.warn("Failed to find OpenLayers.Lang."+a.join("-")+" dictionary, falling back to default language"),
1749 b=OpenLayers.Lang.defaultCode);OpenLayers.Lang.code=b},translate:function(a,b){var c=OpenLayers.Lang[OpenLayers.Lang.getCode()];(c=c&&c[a])||(c=a);b&&(c=OpenLayers.String.format(c,b));return c}};OpenLayers.i18n=OpenLayers.Lang.translate;OpenLayers.Util=OpenLayers.Util||{};OpenLayers.Util.getElement=function(){for(var a=[],b=0,c=arguments.length;b<c;b++){var d=arguments[b];"string"==typeof d&&(d=document.getElementById(d));if(1==arguments.length)return d;a.push(d)}return a};OpenLayers.Util.isElement=function(a){return!!(a&&1===a.nodeType)};OpenLayers.Util.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)};"undefined"===typeof window.$&&(window.$=OpenLayers.Util.getElement);
1750 OpenLayers.Util.removeItem=function(a,b){for(var c=a.length-1;c>=0;c--)a[c]==b&&a.splice(c,1);return a};OpenLayers.Util.indexOf=function(a,b){if(typeof a.indexOf=="function")return a.indexOf(b);for(var c=0,d=a.length;c<d;c++)if(a[c]==b)return c;return-1};
1751 OpenLayers.Util.modifyDOMElement=function(a,b,c,d,e,f,g,h){if(b)a.id=b;if(c){a.style.left=c.x+"px";a.style.top=c.y+"px"}if(d){a.style.width=d.w+"px";a.style.height=d.h+"px"}if(e)a.style.position=e;if(f)a.style.border=f;if(g)a.style.overflow=g;if(parseFloat(h)>=0&&parseFloat(h)<1){a.style.filter="alpha(opacity="+h*100+")";a.style.opacity=h}else if(parseFloat(h)==1){a.style.filter="";a.style.opacity=""}};
1752 OpenLayers.Util.createDiv=function(a,b,c,d,e,f,g,h){var i=document.createElement("div");if(d)i.style.backgroundImage="url("+d+")";a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="absolute");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,g,h);return i};
1753 OpenLayers.Util.createImage=function(a,b,c,d,e,f,g,h){var i=document.createElement("img");a||(a=OpenLayers.Util.createUniqueID("OpenLayersDiv"));e||(e="relative");OpenLayers.Util.modifyDOMElement(i,a,b,c,e,f,null,g);if(h){i.style.display="none";b=function(){i.style.display="";OpenLayers.Event.stopObservingElement(i)};OpenLayers.Event.observe(i,"load",b);OpenLayers.Event.observe(i,"error",b)}i.style.alt=a;i.galleryImg="no";if(d)i.src=d;return i};OpenLayers.IMAGE_RELOAD_ATTEMPTS=0;
1754 OpenLayers.Util.alphaHackNeeded=null;OpenLayers.Util.alphaHack=function(){if(OpenLayers.Util.alphaHackNeeded==null){var a=navigator.appVersion.split("MSIE"),a=parseFloat(a[1]),b=false;try{b=!!document.body.filters}catch(c){}OpenLayers.Util.alphaHackNeeded=b&&a>=5.5&&a<7}return OpenLayers.Util.alphaHackNeeded};
1755 OpenLayers.Util.modifyAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){OpenLayers.Util.modifyDOMElement(a,b,c,d,f,null,null,i);b=a.childNodes[0];if(e)b.src=e;OpenLayers.Util.modifyDOMElement(b,a.id+"_innerImage",null,d,"relative",g);if(OpenLayers.Util.alphaHack()){if(a.style.display!="none")a.style.display="inline-block";h==null&&(h="scale");a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+b.src+"', sizingMethod='"+h+"')";if(parseFloat(a.style.opacity)>=0&&parseFloat(a.style.opacity)<
1756 1)a.style.filter=a.style.filter+(" alpha(opacity="+a.style.opacity*100+")");b.style.filter="alpha(opacity=0)"}};OpenLayers.Util.createAlphaImageDiv=function(a,b,c,d,e,f,g,h,i){var j=OpenLayers.Util.createDiv(),i=OpenLayers.Util.createImage(null,null,null,null,null,null,null,i);i.className="olAlphaImg";j.appendChild(i);OpenLayers.Util.modifyAlphaImageDiv(j,a,b,c,d,e,f,g,h);return j};OpenLayers.Util.upperCaseObject=function(a){var b={},c;for(c in a)b[c.toUpperCase()]=a[c];return b};
1757 OpenLayers.Util.applyDefaults=function(a,b){var a=a||{},c=typeof window.Event=="function"&&b instanceof window.Event,d;for(d in b)if(a[d]===void 0||!c&&b.hasOwnProperty&&b.hasOwnProperty(d)&&!a.hasOwnProperty(d))a[d]=b[d];if(!c&&b&&b.hasOwnProperty&&b.hasOwnProperty("toString")&&!a.hasOwnProperty("toString"))a.toString=b.toString;return a};
1758 OpenLayers.Util.getParameterString=function(a){var b=[],c;for(c in a){var d=a[c];if(d!=null&&typeof d!="function"){if(typeof d=="object"&&d.constructor==Array){for(var e=[],f,g=0,h=d.length;g<h;g++){f=d[g];e.push(encodeURIComponent(f===null||f===void 0?"":f))}d=e.join(",")}else d=encodeURIComponent(d);b.push(encodeURIComponent(c)+"="+d)}}return b.join("&")};OpenLayers.Util.urlAppend=function(a,b){var c=a;if(b)var d=(a+" ").split(/[?&]/),c=c+(d.pop()===" "?b:d.length?"&"+b:"?"+b);return c};
1759 OpenLayers.Util.getImagesLocation=function(){return OpenLayers.ImgPath||OpenLayers._getScriptLocation()+"img/"};OpenLayers.Util.getImageLocation=function(a){return OpenLayers.Util.getImagesLocation()+a};OpenLayers.Util.Try=function(){for(var a=null,b=0,c=arguments.length;b<c;b++){var d=arguments[b];try{a=d();break}catch(e){}}return a};
1760 OpenLayers.Util.getXmlNodeValue=function(a){var b=null;OpenLayers.Util.Try(function(){b=a.text;if(!b)b=a.textContent;if(!b)b=a.firstChild.nodeValue},function(){b=a.textContent});return b};OpenLayers.Util.mouseLeft=function(a,b){for(var c=a.relatedTarget?a.relatedTarget:a.toElement;c!=b&&c!=null;)c=c.parentNode;return c!=b};OpenLayers.Util.DEFAULT_PRECISION=14;
1761 OpenLayers.Util.toFloat=function(a,b){if(b==null)b=OpenLayers.Util.DEFAULT_PRECISION;typeof a!=="number"&&(a=parseFloat(a));return b===0?a:parseFloat(a.toPrecision(b))};OpenLayers.Util.rad=function(a){return a*Math.PI/180};OpenLayers.Util.deg=function(a){return a*180/Math.PI};OpenLayers.Util.VincentyConstants={a:6378137,b:6356752.3142,f:1/298.257223563};
1762 OpenLayers.Util.distVincenty=function(a,b){for(var c=OpenLayers.Util.VincentyConstants,d=c.a,e=c.b,c=c.f,f=OpenLayers.Util.rad(b.lon-a.lon),g=Math.atan((1-c)*Math.tan(OpenLayers.Util.rad(a.lat))),h=Math.atan((1-c)*Math.tan(OpenLayers.Util.rad(b.lat))),i=Math.sin(g),g=Math.cos(g),j=Math.sin(h),h=Math.cos(h),k=f,l=2*Math.PI,m=20;Math.abs(k-l)>1.0E-12&&--m>0;){var n=Math.sin(k),o=Math.cos(k),p=Math.sqrt(h*n*h*n+(g*j-i*h*o)*(g*j-i*h*o));if(p==0)return 0;var o=i*j+g*h*o,q=Math.atan2(p,o),r=Math.asin(g*
1763 h*n/p),s=Math.cos(r)*Math.cos(r),n=o-2*i*j/s,t=c/16*s*(4+c*(4-3*s)),l=k,k=f+(1-t)*c*Math.sin(r)*(q+t*p*(n+t*o*(-1+2*n*n)))}if(m==0)return NaN;d=s*(d*d-e*e)/(e*e);c=d/1024*(256+d*(-128+d*(74-47*d)));return(e*(1+d/16384*(4096+d*(-768+d*(320-175*d))))*(q-c*p*(n+c/4*(o*(-1+2*n*n)-c/6*n*(-3+4*p*p)*(-3+4*n*n))))).toFixed(3)/1E3};
1764 OpenLayers.Util.destinationVincenty=function(a,b,c){for(var d=OpenLayers.Util,e=d.VincentyConstants,f=e.a,g=e.b,h=e.f,e=a.lon,a=a.lat,i=d.rad(b),b=Math.sin(i),i=Math.cos(i),a=(1-h)*Math.tan(d.rad(a)),j=1/Math.sqrt(1+a*a),k=a*j,l=Math.atan2(a,i),a=j*b,m=1-a*a,f=m*(f*f-g*g)/(g*g),n=1+f/16384*(4096+f*(-768+f*(320-175*f))),o=f/1024*(256+f*(-128+f*(74-47*f))),f=c/(g*n),p=2*Math.PI;Math.abs(f-p)>1.0E-12;)var q=Math.cos(2*l+f),r=Math.sin(f),s=Math.cos(f),t=o*r*(q+o/4*(s*(-1+2*q*q)-o/6*q*(-3+4*r*r)*(-3+4*
1765 q*q))),p=f,f=c/(g*n)+t;c=k*r-j*s*i;g=Math.atan2(k*s+j*r*i,(1-h)*Math.sqrt(a*a+c*c));b=Math.atan2(r*b,j*s-k*r*i);i=h/16*m*(4+h*(4-3*m));q=b-(1-i)*h*a*(f+i*r*(q+i*s*(-1+2*q*q)));Math.atan2(a,-c);return new OpenLayers.LonLat(e+d.deg(q),d.deg(g))};
1766 OpenLayers.Util.getParameters=function(a){var a=a===null||a===void 0?window.location.href:a,b="";if(OpenLayers.String.contains(a,"?"))var b=a.indexOf("?")+1,c=OpenLayers.String.contains(a,"#")?a.indexOf("#"):a.length,b=a.substring(b,c);for(var a={},b=b.split(/[&;]/),c=0,d=b.length;c<d;++c){var e=b[c].split("=");if(e[0]){var f=e[0];try{f=decodeURIComponent(f)}catch(g){f=unescape(f)}e=(e[1]||"").replace(/\+/g," ");try{e=decodeURIComponent(e)}catch(h){e=unescape(e)}e=e.split(",");e.length==1&&(e=e[0]);
1767 a[f]=e}}return a};OpenLayers.Util.lastSeqID=0;OpenLayers.Util.createUniqueID=function(a){a==null&&(a="id_");OpenLayers.Util.lastSeqID=OpenLayers.Util.lastSeqID+1;return a+OpenLayers.Util.lastSeqID};OpenLayers.INCHES_PER_UNIT={inches:1,ft:12,mi:63360,m:39.3701,km:39370.1,dd:4374754,yd:36};OpenLayers.INCHES_PER_UNIT["in"]=OpenLayers.INCHES_PER_UNIT.inches;OpenLayers.INCHES_PER_UNIT.degrees=OpenLayers.INCHES_PER_UNIT.dd;OpenLayers.INCHES_PER_UNIT.nmi=1852*OpenLayers.INCHES_PER_UNIT.m;
1768 OpenLayers.METERS_PER_INCH=0.0254000508001016;
1769 OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{Inch:OpenLayers.INCHES_PER_UNIT.inches,Meter:1/OpenLayers.METERS_PER_INCH,Foot:0.3048006096012192/OpenLayers.METERS_PER_INCH,IFoot:0.3048/OpenLayers.METERS_PER_INCH,ClarkeFoot:0.3047972651151/OpenLayers.METERS_PER_INCH,SearsFoot:0.30479947153867626/OpenLayers.METERS_PER_INCH,GoldCoastFoot:0.3047997101815088/OpenLayers.METERS_PER_INCH,IInch:0.0254/OpenLayers.METERS_PER_INCH,MicroInch:2.54E-5/OpenLayers.METERS_PER_INCH,Mil:2.54E-8/OpenLayers.METERS_PER_INCH,
1770 Centimeter:0.01/OpenLayers.METERS_PER_INCH,Kilometer:1E3/OpenLayers.METERS_PER_INCH,Yard:0.9144018288036576/OpenLayers.METERS_PER_INCH,SearsYard:0.914398414616029/OpenLayers.METERS_PER_INCH,IndianYard:0.9143985307444408/OpenLayers.METERS_PER_INCH,IndianYd37:0.91439523/OpenLayers.METERS_PER_INCH,IndianYd62:0.9143988/OpenLayers.METERS_PER_INCH,IndianYd75:0.9143985/OpenLayers.METERS_PER_INCH,IndianFoot:0.30479951/OpenLayers.METERS_PER_INCH,IndianFt37:0.30479841/OpenLayers.METERS_PER_INCH,IndianFt62:0.3047996/
1771 OpenLayers.METERS_PER_INCH,IndianFt75:0.3047995/OpenLayers.METERS_PER_INCH,Mile:1609.3472186944373/OpenLayers.METERS_PER_INCH,IYard:0.9144/OpenLayers.METERS_PER_INCH,IMile:1609.344/OpenLayers.METERS_PER_INCH,NautM:1852/OpenLayers.METERS_PER_INCH,"Lat-66":110943.31648893273/OpenLayers.METERS_PER_INCH,"Lat-83":110946.25736872235/OpenLayers.METERS_PER_INCH,Decimeter:0.1/OpenLayers.METERS_PER_INCH,Millimeter:0.001/OpenLayers.METERS_PER_INCH,Dekameter:10/OpenLayers.METERS_PER_INCH,Decameter:10/OpenLayers.METERS_PER_INCH,
1772 Hectometer:100/OpenLayers.METERS_PER_INCH,GermanMeter:1.0000135965/OpenLayers.METERS_PER_INCH,CaGrid:0.999738/OpenLayers.METERS_PER_INCH,ClarkeChain:20.1166194976/OpenLayers.METERS_PER_INCH,GunterChain:20.11684023368047/OpenLayers.METERS_PER_INCH,BenoitChain:20.116782494375872/OpenLayers.METERS_PER_INCH,SearsChain:20.11676512155/OpenLayers.METERS_PER_INCH,ClarkeLink:0.201166194976/OpenLayers.METERS_PER_INCH,GunterLink:0.2011684023368047/OpenLayers.METERS_PER_INCH,BenoitLink:0.20116782494375873/OpenLayers.METERS_PER_INCH,
1773 SearsLink:0.2011676512155/OpenLayers.METERS_PER_INCH,Rod:5.02921005842012/OpenLayers.METERS_PER_INCH,IntnlChain:20.1168/OpenLayers.METERS_PER_INCH,IntnlLink:0.201168/OpenLayers.METERS_PER_INCH,Perch:5.02921005842012/OpenLayers.METERS_PER_INCH,Pole:5.02921005842012/OpenLayers.METERS_PER_INCH,Furlong:201.1684023368046/OpenLayers.METERS_PER_INCH,Rood:3.778266898/OpenLayers.METERS_PER_INCH,CapeFoot:0.3047972615/OpenLayers.METERS_PER_INCH,Brealey:375/OpenLayers.METERS_PER_INCH,ModAmFt:0.304812252984506/
1774 OpenLayers.METERS_PER_INCH,Fathom:1.8288/OpenLayers.METERS_PER_INCH,"NautM-UK":1853.184/OpenLayers.METERS_PER_INCH,"50kilometers":5E4/OpenLayers.METERS_PER_INCH,"150kilometers":15E4/OpenLayers.METERS_PER_INCH});
1775 OpenLayers.Util.extend(OpenLayers.INCHES_PER_UNIT,{mm:OpenLayers.INCHES_PER_UNIT.Meter/1E3,cm:OpenLayers.INCHES_PER_UNIT.Meter/100,dm:100*OpenLayers.INCHES_PER_UNIT.Meter,km:1E3*OpenLayers.INCHES_PER_UNIT.Meter,kmi:OpenLayers.INCHES_PER_UNIT.nmi,fath:OpenLayers.INCHES_PER_UNIT.Fathom,ch:OpenLayers.INCHES_PER_UNIT.IntnlChain,link:OpenLayers.INCHES_PER_UNIT.IntnlLink,"us-in":OpenLayers.INCHES_PER_UNIT.inches,"us-ft":OpenLayers.INCHES_PER_UNIT.Foot,"us-yd":OpenLayers.INCHES_PER_UNIT.Yard,"us-ch":OpenLayers.INCHES_PER_UNIT.GunterChain,
1776 "us-mi":OpenLayers.INCHES_PER_UNIT.Mile,"ind-yd":OpenLayers.INCHES_PER_UNIT.IndianYd37,"ind-ft":OpenLayers.INCHES_PER_UNIT.IndianFt37,"ind-ch":20.11669506/OpenLayers.METERS_PER_INCH});OpenLayers.DOTS_PER_INCH=72;OpenLayers.Util.normalizeScale=function(a){return a>1?1/a:a};OpenLayers.Util.getResolutionFromScale=function(a,b){var c;if(a){b==null&&(b="degrees");c=1/(OpenLayers.Util.normalizeScale(a)*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH)}return c};
1777 OpenLayers.Util.getScaleFromResolution=function(a,b){b==null&&(b="degrees");return a*OpenLayers.INCHES_PER_UNIT[b]*OpenLayers.DOTS_PER_INCH};
1778 OpenLayers.Util.pagePosition=function(a){var b=[0,0],c=OpenLayers.Util.getViewportElement();if(!a||a==window||a==c)return b;var d=OpenLayers.IS_GECKO&&document.getBoxObjectFor&&OpenLayers.Element.getStyle(a,"position")=="absolute"&&(a.style.top==""||a.style.left==""),e=null;if(a.getBoundingClientRect){a=a.getBoundingClientRect();e=c.scrollTop;b[0]=a.left+c.scrollLeft;b[1]=a.top+e}else if(document.getBoxObjectFor&&!d){a=document.getBoxObjectFor(a);c=document.getBoxObjectFor(c);b[0]=a.screenX-c.screenX;
1779 b[1]=a.screenY-c.screenY}else{b[0]=a.offsetLeft;b[1]=a.offsetTop;e=a.offsetParent;if(e!=a)for(;e;){b[0]=b[0]+e.offsetLeft;b[1]=b[1]+e.offsetTop;e=e.offsetParent}c=OpenLayers.BROWSER_NAME;if(c=="opera"||c=="safari"&&OpenLayers.Element.getStyle(a,"position")=="absolute")b[1]=b[1]-document.body.offsetTop;for(e=a.offsetParent;e&&e!=document.body;){b[0]=b[0]-e.scrollLeft;if(c!="opera"||e.tagName!="TR")b[1]=b[1]-e.scrollTop;e=e.offsetParent}}return b};
1780 OpenLayers.Util.getViewportElement=function(){var a=arguments.callee.viewportElement;if(a==void 0){a=OpenLayers.BROWSER_NAME=="msie"&&document.compatMode!="CSS1Compat"?document.body:document.documentElement;arguments.callee.viewportElement=a}return a};
1781 OpenLayers.Util.isEquivalentUrl=function(a,b,c){c=c||{};OpenLayers.Util.applyDefaults(c,{ignoreCase:true,ignorePort80:true,ignoreHash:true});var a=OpenLayers.Util.createUrlObject(a,c),b=OpenLayers.Util.createUrlObject(b,c),d;for(d in a)if(d!=="args"&&a[d]!=b[d])return false;for(d in a.args){if(a.args[d]!=b.args[d])return false;delete b.args[d]}for(d in b.args)return false;return true};
1782 OpenLayers.Util.createUrlObject=function(a,b){b=b||{};if(!/^\w+:\/\//.test(a)){var c=window.location,d=c.port?":"+c.port:"",d=c.protocol+"//"+c.host.split(":").shift()+d;if(a.indexOf("/")===0)a=d+a;else{c=c.pathname.split("/");c.pop();a=d+c.join("/")+"/"+a}}b.ignoreCase&&(a=a.toLowerCase());c=document.createElement("a");c.href=a;d={};d.host=c.host.split(":").shift();d.protocol=c.protocol;d.port=b.ignorePort80?c.port=="80"||c.port=="0"?"":c.port:c.port==""||c.port=="0"?"80":c.port;d.hash=b.ignoreHash||
1783 c.hash==="#"?"":c.hash;var e=c.search;if(!e){e=a.indexOf("?");e=e!=-1?a.substr(e):""}d.args=OpenLayers.Util.getParameters(e);d.pathname=c.pathname.charAt(0)=="/"?c.pathname:"/"+c.pathname;return d};OpenLayers.Util.removeTail=function(a){var b=null,b=a.indexOf("?"),c=a.indexOf("#");return b=b==-1?c!=-1?a.substr(0,c):a:c!=-1?a.substr(0,Math.min(b,c)):a.substr(0,b)};OpenLayers.IS_GECKO=function(){var a=navigator.userAgent.toLowerCase();return a.indexOf("webkit")==-1&&a.indexOf("gecko")!=-1}();
1784 OpenLayers.CANVAS_SUPPORTED=function(){var a=document.createElement("canvas");return!(!a.getContext||!a.getContext("2d"))}();OpenLayers.BROWSER_NAME=function(){var a="",b=navigator.userAgent.toLowerCase();b.indexOf("opera")!=-1?a="opera":b.indexOf("msie")!=-1?a="msie":b.indexOf("safari")!=-1?a="safari":b.indexOf("mozilla")!=-1&&(a=b.indexOf("firefox")!=-1?"firefox":"mozilla");return a}();OpenLayers.Util.getBrowserName=function(){return OpenLayers.BROWSER_NAME};
1785 OpenLayers.Util.getRenderedDimensions=function(a,b,c){var d,e,f=document.createElement("div");f.style.visibility="hidden";for(var g=c&&c.containerElement?c.containerElement:document.body,h=false,i=null,j=g;j&&j.tagName.toLowerCase()!="body";){var k=OpenLayers.Element.getStyle(j,"position");if(k=="absolute"){h=true;break}else if(k&&k!="static")break;j=j.parentNode}if(h&&(g.clientHeight===0||g.clientWidth===0)){i=document.createElement("div");i.style.visibility="hidden";i.style.position="absolute";
1786 i.style.overflow="visible";i.style.width=document.body.clientWidth+"px";i.style.height=document.body.clientHeight+"px";i.appendChild(f)}f.style.position="absolute";if(b)if(b.w){d=b.w;f.style.width=d+"px"}else if(b.h){e=b.h;f.style.height=e+"px"}if(c&&c.displayClass)f.className=c.displayClass;b=document.createElement("div");b.innerHTML=a;b.style.overflow="visible";if(b.childNodes){a=0;for(c=b.childNodes.length;a<c;a++)if(b.childNodes[a].style)b.childNodes[a].style.overflow="visible"}f.appendChild(b);
1787 i?g.appendChild(i):g.appendChild(f);if(!d){d=parseInt(b.scrollWidth);f.style.width=d+"px"}e||(e=parseInt(b.scrollHeight));f.removeChild(b);if(i){i.removeChild(f);g.removeChild(i)}else g.removeChild(f);return new OpenLayers.Size(d,e)};
1788 OpenLayers.Util.getScrollbarWidth=function(){var a=OpenLayers.Util._scrollbarWidth;if(a==null){var b=null,c=null,b=a=0,b=document.createElement("div");b.style.position="absolute";b.style.top="-1000px";b.style.left="-1000px";b.style.width="100px";b.style.height="50px";b.style.overflow="hidden";c=document.createElement("div");c.style.width="100%";c.style.height="200px";b.appendChild(c);document.body.appendChild(b);a=c.offsetWidth;b.style.overflow="scroll";b=c.offsetWidth;document.body.removeChild(document.body.lastChild);
1789 OpenLayers.Util._scrollbarWidth=a-b;a=OpenLayers.Util._scrollbarWidth}return a};
1790 OpenLayers.Util.getFormattedLonLat=function(a,b,c){c||(c="dms");var a=(a+540)%360-180,d=Math.abs(a),e=Math.floor(d),f=d=(d-e)/(1/60),d=Math.floor(d),f=Math.round((f-d)/(1/60)*10),f=f/10;if(f>=60){f=f-60;d=d+1;if(d>=60){d=d-60;e=e+1}}e<10&&(e="0"+e);e=e+"\u00b0";if(c.indexOf("dm")>=0){d<10&&(d="0"+d);e=e+(d+"'");if(c.indexOf("dms")>=0){f<10&&(f="0"+f);e=e+(f+'"')}}return e=b=="lon"?e+(a<0?OpenLayers.i18n("W"):OpenLayers.i18n("E")):e+(a<0?OpenLayers.i18n("S"):OpenLayers.i18n("N"))};OpenLayers.Format=OpenLayers.Class({options:null,externalProjection:null,internalProjection:null,data:null,keepData:!1,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a},destroy:function(){},read:function(){throw Error("Read not implemented.");},write:function(){throw Error("Write not implemented.");},CLASS_NAME:"OpenLayers.Format"});OpenLayers.Format.CSWGetRecords=function(a){var a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.CSWGetRecords.DEFAULTS),b=OpenLayers.Format.CSWGetRecords["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSWGetRecords version: "+a.version;return new b(a)};OpenLayers.Format.CSWGetRecords.DEFAULTS={version:"2.0.2"};OpenLayers.Control=OpenLayers.Class({id:null,map:null,div:null,type:null,allowSelection:!1,displayClass:"",title:"",autoActivate:!1,active:null,handler:null,eventListeners:null,events:null,initialize:function(a){this.displayClass=this.CLASS_NAME.replace("OpenLayers.","ol").replace(/\./g,"");OpenLayers.Util.extend(this,a);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object)this.events.on(this.eventListeners);null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+
1791 "_"))},destroy:function(){this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy(),this.events=null);this.eventListeners=null;this.handler&&(this.handler.destroy(),this.handler=null);if(this.handlers){for(var a in this.handlers)this.handlers.hasOwnProperty(a)&&"function"==typeof this.handlers[a].destroy&&this.handlers[a].destroy();this.handlers=null}this.map&&(this.map.removeControl(this),this.map=null);this.div=null},setMap:function(a){this.map=a;this.handler&&
1792 this.handler.setMap(a)},draw:function(a){if(null==this.div&&(this.div=OpenLayers.Util.createDiv(this.id),this.div.className=this.displayClass,this.allowSelection||(this.div.className+=" olControlNoSelect",this.div.setAttribute("unselectable","on",0),this.div.onselectstart=OpenLayers.Function.False),""!=this.title))this.div.title=this.title;null!=a&&(this.position=a.clone());this.moveTo(this.position);return this.div},moveTo:function(a){null!=a&&null!=this.div&&(this.div.style.left=a.x+"px",this.div.style.top=
1793 a.y+"px")},activate:function(){if(this.active)return!1;this.handler&&this.handler.activate();this.active=!0;this.map&&OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active");this.events.triggerEvent("activate");return!0},deactivate:function(){return this.active?(this.handler&&this.handler.deactivate(),this.active=!1,this.map&&OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass.replace(/ /g,"")+"Active"),this.events.triggerEvent("deactivate"),
1794 !0):!1},CLASS_NAME:"OpenLayers.Control"});OpenLayers.Control.TYPE_BUTTON=1;OpenLayers.Control.TYPE_TOGGLE=2;OpenLayers.Control.TYPE_TOOL=3;OpenLayers.Event={observers:!1,KEY_SPACE:32,KEY_BACKSPACE:8,KEY_TAB:9,KEY_RETURN:13,KEY_ESC:27,KEY_LEFT:37,KEY_UP:38,KEY_RIGHT:39,KEY_DOWN:40,KEY_DELETE:46,element:function(a){return a.target||a.srcElement},isSingleTouch:function(a){return a.touches&&1==a.touches.length},isMultiTouch:function(a){return a.touches&&1<a.touches.length},isLeftClick:function(a){return a.which&&1==a.which||a.button&&1==a.button},isRightClick:function(a){return a.which&&3==a.which||a.button&&2==a.button},stop:function(a,
1795 b){b||(a.preventDefault?a.preventDefault():a.returnValue=!1);a.stopPropagation?a.stopPropagation():a.cancelBubble=!0},findElement:function(a,b){for(var c=OpenLayers.Event.element(a);c.parentNode&&(!c.tagName||c.tagName.toUpperCase()!=b.toUpperCase());)c=c.parentNode;return c},observe:function(a,b,c,d){a=OpenLayers.Util.getElement(a);d=d||!1;if("keypress"==b&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.attachEvent))b="keydown";this.observers||(this.observers={});if(!a._eventCacheID){var e=
1796 "eventCacheID_";a.id&&(e=a.id+"_"+e);a._eventCacheID=OpenLayers.Util.createUniqueID(e)}e=a._eventCacheID;this.observers[e]||(this.observers[e]=[]);this.observers[e].push({element:a,name:b,observer:c,useCapture:d});a.addEventListener?a.addEventListener(b,c,d):a.attachEvent&&a.attachEvent("on"+b,c)},stopObservingElement:function(a){a=OpenLayers.Util.getElement(a)._eventCacheID;this._removeElementObservers(OpenLayers.Event.observers[a])},_removeElementObservers:function(a){if(a)for(var b=a.length-1;0<=
1797 b;b--){var c=a[b];OpenLayers.Event.stopObserving.apply(this,[c.element,c.name,c.observer,c.useCapture])}},stopObserving:function(a,b,c,d){var d=d||!1,a=OpenLayers.Util.getElement(a),e=a._eventCacheID;if("keypress"==b&&(navigator.appVersion.match(/Konqueror|Safari|KHTML/)||a.detachEvent))b="keydown";var f=!1,g=OpenLayers.Event.observers[e];if(g)for(var h=0;!f&&h<g.length;){var i=g[h];if(i.name==b&&i.observer==c&&i.useCapture==d){g.splice(h,1);0==g.length&&delete OpenLayers.Event.observers[e];f=!0;
1798 break}h++}f&&(a.removeEventListener?a.removeEventListener(b,c,d):a&&a.detachEvent&&a.detachEvent("on"+b,c));return f},unloadCache:function(){if(OpenLayers.Event&&OpenLayers.Event.observers){for(var a in OpenLayers.Event.observers)OpenLayers.Event._removeElementObservers.apply(this,[OpenLayers.Event.observers[a]]);OpenLayers.Event.observers=!1}},CLASS_NAME:"OpenLayers.Event"};OpenLayers.Event.observe(window,"unload",OpenLayers.Event.unloadCache,!1);
1799 OpenLayers.Events=OpenLayers.Class({BROWSER_EVENTS:"mouseover mouseout mousedown mouseup mousemove click dblclick rightclick dblrightclick resize focus blur touchstart touchmove touchend keydown".split(" "),listeners:null,object:null,element:null,eventHandler:null,fallThrough:null,includeXY:!1,extensions:null,extensionCount:null,clearMouseListener:null,initialize:function(a,b,c,d,e){OpenLayers.Util.extend(this,e);this.object=a;this.fallThrough=d;this.listeners={};this.extensions={};this.extensionCount=
1800 {};null!=b&&this.attachToElement(b)},destroy:function(){for(var a in this.extensions)"boolean"!==typeof this.extensions[a]&&this.extensions[a].destroy();this.extensions=null;this.element&&(OpenLayers.Event.stopObservingElement(this.element),this.element.hasScrollEvent&&OpenLayers.Event.stopObserving(window,"scroll",this.clearMouseListener));this.eventHandler=this.fallThrough=this.object=this.listeners=this.element=null},addEventType:function(){},attachToElement:function(a){this.element?OpenLayers.Event.stopObservingElement(this.element):
1801 (this.eventHandler=OpenLayers.Function.bindAsEventListener(this.handleBrowserEvent,this),this.clearMouseListener=OpenLayers.Function.bind(this.clearMouseCache,this));this.element=a;for(var b=0,c=this.BROWSER_EVENTS.length;b<c;b++)OpenLayers.Event.observe(a,this.BROWSER_EVENTS[b],this.eventHandler);OpenLayers.Event.observe(a,"dragstart",OpenLayers.Event.stop)},on:function(a){for(var b in a)"scope"!=b&&a.hasOwnProperty(b)&&this.register(b,a.scope,a[b])},register:function(a,b,c,d){a in OpenLayers.Events&&
1802 !this.extensions[a]&&(this.extensions[a]=new OpenLayers.Events[a](this));if(null!=c){null==b&&(b=this.object);var e=this.listeners[a];e||(e=[],this.listeners[a]=e,this.extensionCount[a]=0);b={obj:b,func:c};d?(e.splice(this.extensionCount[a],0,b),"object"===typeof d&&d.extension&&this.extensionCount[a]++):e.push(b)}},registerPriority:function(a,b,c){this.register(a,b,c,!0)},un:function(a){for(var b in a)"scope"!=b&&a.hasOwnProperty(b)&&this.unregister(b,a.scope,a[b])},unregister:function(a,b,c){null==
1803 b&&(b=this.object);a=this.listeners[a];if(null!=a)for(var d=0,e=a.length;d<e;d++)if(a[d].obj==b&&a[d].func==c){a.splice(d,1);break}},remove:function(a){null!=this.listeners[a]&&(this.listeners[a]=[])},triggerEvent:function(a,b){var c=this.listeners[a];if(c&&0!=c.length){null==b&&(b={});b.object=this.object;b.element=this.element;b.type||(b.type=a);for(var c=c.slice(),d,e=0,f=c.length;e<f&&!(d=c[e],d=d.func.apply(d.obj,[b]),void 0!=d&&!1==d);e++);this.fallThrough||OpenLayers.Event.stop(b,!0);return d}},
1804 handleBrowserEvent:function(a){var b=a.type,c=this.listeners[b];if(c&&0!=c.length){if((c=a.touches)&&c[0]){for(var d=0,e=0,f=c.length,g,h=0;h<f;++h)g=c[h],d+=g.clientX,e+=g.clientY;a.clientX=d/f;a.clientY=e/f}this.includeXY&&(a.xy=this.getMousePosition(a));this.triggerEvent(b,a)}},clearMouseCache:function(){this.element.scrolls=null;this.element.lefttop=null;var a=document.body;if(a&&(!(0!=a.scrollTop||0!=a.scrollLeft)||!navigator.userAgent.match(/iPhone/i)))this.element.offsets=null},getMousePosition:function(a){this.includeXY?
1805 this.element.hasScrollEvent||(OpenLayers.Event.observe(window,"scroll",this.clearMouseListener),this.element.hasScrollEvent=!0):this.clearMouseCache();if(!this.element.scrolls){var b=OpenLayers.Util.getViewportElement();this.element.scrolls=[b.scrollLeft,b.scrollTop]}this.element.lefttop||(this.element.lefttop=[document.documentElement.clientLeft||0,document.documentElement.clientTop||0]);this.element.offsets||(this.element.offsets=OpenLayers.Util.pagePosition(this.element));return new OpenLayers.Pixel(a.clientX+
1806 this.element.scrolls[0]-this.element.offsets[0]-this.element.lefttop[0],a.clientY+this.element.scrolls[1]-this.element.offsets[1]-this.element.lefttop[1])},CLASS_NAME:"OpenLayers.Events"});OpenLayers.Events.buttonclick=OpenLayers.Class({target:null,events:"mousedown mouseup click dblclick touchstart touchmove touchend keydown".split(" "),startRegEx:/^mousedown|touchstart$/,cancelRegEx:/^touchmove$/,completeRegEx:/^mouseup|touchend$/,initialize:function(a){this.target=a;for(a=this.events.length-1;0<=a;--a)this.target.register(this.events[a],this,this.buttonClick,{extension:!0})},destroy:function(){for(var a=this.events.length-1;0<=a;--a)this.target.unregister(this.events[a],this,this.buttonClick);
1807 delete this.target},getPressedButton:function(a){var b=3,c;do{if(OpenLayers.Element.hasClass(a,"olButton")){c=a;break}a=a.parentNode}while(0<--b&&a);return c},buttonClick:function(a){var b=!0,c=OpenLayers.Event.element(a);if(c&&(OpenLayers.Event.isLeftClick(a)||!~a.type.indexOf("mouse")))if(c=this.getPressedButton(c)){if("keydown"===a.type)switch(a.keyCode){case OpenLayers.Event.KEY_RETURN:case OpenLayers.Event.KEY_SPACE:this.target.triggerEvent("buttonclick",{buttonElement:c}),OpenLayers.Event.stop(a),
1808 b=!1}else this.startEvt&&(this.completeRegEx.test(a.type)&&(b=OpenLayers.Util.pagePosition(c),this.target.triggerEvent("buttonclick",{buttonElement:c,buttonXY:{x:this.startEvt.clientX-b[0],y:this.startEvt.clientY-b[1]}})),this.cancelRegEx.test(a.type)&&delete this.startEvt,OpenLayers.Event.stop(a),b=!1);this.startRegEx.test(a.type)&&(this.startEvt=a,OpenLayers.Event.stop(a),b=!1)}else delete this.startEvt;return b}});OpenLayers.Control.OverviewMap=OpenLayers.Class(OpenLayers.Control,{element:null,ovmap:null,size:{w:180,h:90},layers:null,minRectSize:15,minRectDisplayClass:"RectReplacement",minRatio:8,maxRatio:32,mapOptions:null,autoPan:!1,handlers:null,resolutionFactor:1,maximized:!1,initialize:function(a){this.layers=[];this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,[a])},destroy:function(){this.mapDiv&&(this.handlers.click&&this.handlers.click.destroy(),this.handlers.drag&&this.handlers.drag.destroy(),
1809 this.ovmap&&this.ovmap.viewPortDiv.removeChild(this.extentRectangle),this.extentRectangle=null,this.rectEvents&&(this.rectEvents.destroy(),this.rectEvents=null),this.ovmap&&(this.ovmap.destroy(),this.ovmap=null),this.element.removeChild(this.mapDiv),this.mapDiv=null,this.div.removeChild(this.element),this.element=null,this.maximizeDiv&&(this.div.removeChild(this.maximizeDiv),this.maximizeDiv=null),this.minimizeDiv&&(this.div.removeChild(this.minimizeDiv),this.minimizeDiv=null),this.map.events.un({buttonclick:this.onButtonClick,
1810 moveend:this.update,changebaselayer:this.baseLayerDraw,scope:this}),OpenLayers.Control.prototype.destroy.apply(this,arguments))},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(0===this.layers.length)if(this.map.baseLayer)this.layers=[this.map.baseLayer.clone()];else return this.map.events.register("changebaselayer",this,this.baseLayerDraw),this.div;this.element=document.createElement("div");this.element.className=this.displayClass+"Element";this.element.style.display="none";
1811 this.mapDiv=document.createElement("div");this.mapDiv.style.width=this.size.w+"px";this.mapDiv.style.height=this.size.h+"px";this.mapDiv.style.position="relative";this.mapDiv.style.overflow="hidden";this.mapDiv.id=OpenLayers.Util.createUniqueID("overviewMap");this.extentRectangle=document.createElement("div");this.extentRectangle.style.position="absolute";this.extentRectangle.style.zIndex=1E3;this.extentRectangle.className=this.displayClass+"ExtentRectangle";this.element.appendChild(this.mapDiv);
1812 this.div.appendChild(this.element);if(this.outsideViewport)this.element.style.display="";else{this.div.className+=" "+this.displayClass+"Container";var a=OpenLayers.Util.getImageLocation("layer-switcher-maximize.png");this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv(this.displayClass+"MaximizeButton",null,null,a,"absolute");this.maximizeDiv.style.display="none";this.maximizeDiv.className=this.displayClass+"MaximizeButton olButton";this.div.appendChild(this.maximizeDiv);a=OpenLayers.Util.getImageLocation("layer-switcher-minimize.png");
1813 this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_minimizeDiv",null,null,a,"absolute");this.minimizeDiv.style.display="none";this.minimizeDiv.className=this.displayClass+"MinimizeButton olButton";this.div.appendChild(this.minimizeDiv);this.minimizeControl()}this.map.getExtent()&&this.update();this.map.events.on({buttonclick:this.onButtonClick,moveend:this.update,scope:this});this.maximized&&this.maximizeControl();return this.div},baseLayerDraw:function(){this.draw();this.map.events.unregister("changebaselayer",
1814 this,this.baseLayerDraw)},rectDrag:function(a){var b=this.handlers.drag.last.x-a.x,c=this.handlers.drag.last.y-a.y;if(0!=b||0!=c){var d=this.rectPxBounds.top,e=this.rectPxBounds.left,a=Math.abs(this.rectPxBounds.getHeight()),f=this.rectPxBounds.getWidth(),c=Math.max(0,d-c),c=Math.min(c,this.ovmap.size.h-this.hComp-a),b=Math.max(0,e-b),b=Math.min(b,this.ovmap.size.w-this.wComp-f);this.setRectPxBounds(new OpenLayers.Bounds(b,c+a,b+f,c))}},mapDivClick:function(a){var b=this.rectPxBounds.getCenterPixel(),
1815 c=a.xy.x-b.x,d=a.xy.y-b.y,e=this.rectPxBounds.top,f=this.rectPxBounds.left,a=Math.abs(this.rectPxBounds.getHeight()),b=this.rectPxBounds.getWidth(),d=Math.max(0,e+d),d=Math.min(d,this.ovmap.size.h-a),c=Math.max(0,f+c),c=Math.min(c,this.ovmap.size.w-b);this.setRectPxBounds(new OpenLayers.Bounds(c,d+a,c+b,d));this.updateMapToRect()},onButtonClick:function(a){a.buttonElement===this.minimizeDiv?this.minimizeControl():a.buttonElement===this.maximizeDiv&&this.maximizeControl()},maximizeControl:function(a){this.element.style.display=
1816 "";this.showToggle(!1);null!=a&&OpenLayers.Event.stop(a)},minimizeControl:function(a){this.element.style.display="none";this.showToggle(!0);null!=a&&OpenLayers.Event.stop(a)},showToggle:function(a){this.maximizeDiv.style.display=a?"":"none";this.minimizeDiv.style.display=a?"none":""},update:function(){null==this.ovmap&&this.createMap();(this.autoPan||!this.isSuitableOverview())&&this.updateOverview();this.updateRectToMap()},isSuitableOverview:function(){var a=this.map.getExtent(),b=this.map.maxExtent,
1817 a=new OpenLayers.Bounds(Math.max(a.left,b.left),Math.max(a.bottom,b.bottom),Math.min(a.right,b.right),Math.min(a.top,b.top));this.ovmap.getProjection()!=this.map.getProjection()&&(a=a.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject()));b=this.ovmap.getResolution()/this.map.getResolution();return b>this.minRatio&&b<=this.maxRatio&&this.ovmap.getExtent().containsBounds(a)},updateOverview:function(){var a=this.map.getResolution(),b=this.ovmap.getResolution(),c=b/a;c>this.maxRatio?
1818 b=this.minRatio*a:c<=this.minRatio&&(b=this.maxRatio*a);this.ovmap.getProjection()!=this.map.getProjection()?(a=this.map.center.clone(),a.transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject())):a=this.map.center;this.ovmap.setCenter(a,this.ovmap.getZoomForResolution(b*this.resolutionFactor));this.updateRectToMap()},createMap:function(){var a=OpenLayers.Util.extend({controls:[],maxResolution:"auto",fallThrough:!1},this.mapOptions);this.ovmap=new OpenLayers.Map(this.mapDiv,a);this.ovmap.viewPortDiv.appendChild(this.extentRectangle);
1819 OpenLayers.Event.stopObserving(window,"unload",this.ovmap.unloadDestroy);this.ovmap.addLayers(this.layers);this.ovmap.zoomToMaxExtent();this.wComp=(this.wComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-left-width"))+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-right-width")))?this.wComp:2;this.hComp=(this.hComp=parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-top-width"))+parseInt(OpenLayers.Element.getStyle(this.extentRectangle,"border-bottom-width")))?
1820 this.hComp:2;this.handlers.drag=new OpenLayers.Handler.Drag(this,{move:this.rectDrag,done:this.updateMapToRect},{map:this.ovmap});this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.mapDivClick},{single:!0,"double":!1,stopSingle:!0,stopDouble:!0,pixelTolerance:1,map:this.ovmap});this.handlers.click.activate();this.rectEvents=new OpenLayers.Events(this,this.extentRectangle,null,!0);this.rectEvents.register("mouseover",this,function(){!this.handlers.drag.active&&!this.map.dragging&&this.handlers.drag.activate()});
1821 this.rectEvents.register("mouseout",this,function(){this.handlers.drag.dragging||this.handlers.drag.deactivate()});if(this.ovmap.getProjection()!=this.map.getProjection()){var a=this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units,b=this.ovmap.getProjectionObject().getUnits()||this.ovmap.units||this.ovmap.baseLayer.units;this.resolutionFactor=a&&b?OpenLayers.INCHES_PER_UNIT[a]/OpenLayers.INCHES_PER_UNIT[b]:1}},updateRectToMap:function(){var a=this.getRectBoundsFromMapBounds(this.ovmap.getProjection()!=
1822 this.map.getProjection()?this.map.getExtent().transform(this.map.getProjectionObject(),this.ovmap.getProjectionObject()):this.map.getExtent());a&&this.setRectPxBounds(a)},updateMapToRect:function(){var a=this.getMapBoundsFromRectBounds(this.rectPxBounds);this.ovmap.getProjection()!=this.map.getProjection()&&(a=a.transform(this.ovmap.getProjectionObject(),this.map.getProjectionObject()));this.map.panTo(a.getCenterLonLat())},setRectPxBounds:function(a){var b=Math.max(a.top,0),c=Math.max(a.left,0),d=
1823 Math.min(a.top+Math.abs(a.getHeight()),this.ovmap.size.h-this.hComp),a=Math.min(a.left+a.getWidth(),this.ovmap.size.w-this.wComp),e=Math.max(a-c,0),f=Math.max(d-b,0);e<this.minRectSize||f<this.minRectSize?(this.extentRectangle.className=this.displayClass+this.minRectDisplayClass,e=c+e/2-this.minRectSize/2,this.extentRectangle.style.top=Math.round(b+f/2-this.minRectSize/2)+"px",this.extentRectangle.style.left=Math.round(e)+"px",this.extentRectangle.style.height=this.minRectSize+"px",this.extentRectangle.style.width=
1824 this.minRectSize+"px"):(this.extentRectangle.className=this.displayClass+"ExtentRectangle",this.extentRectangle.style.top=Math.round(b)+"px",this.extentRectangle.style.left=Math.round(c)+"px",this.extentRectangle.style.height=Math.round(f)+"px",this.extentRectangle.style.width=Math.round(e)+"px");this.rectPxBounds=new OpenLayers.Bounds(Math.round(c),Math.round(d),Math.round(a),Math.round(b))},getRectBoundsFromMapBounds:function(a){var b=this.getOverviewPxFromLonLat({lon:a.left,lat:a.bottom}),a=this.getOverviewPxFromLonLat({lon:a.right,
1825 lat:a.top}),c=null;b&&a&&(c=new OpenLayers.Bounds(b.x,b.y,a.x,a.y));return c},getMapBoundsFromRectBounds:function(a){var b=this.getLonLatFromOverviewPx({x:a.left,y:a.bottom}),a=this.getLonLatFromOverviewPx({x:a.right,y:a.top});return new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat)},getLonLatFromOverviewPx:function(a){var b=this.ovmap.size,c=this.ovmap.getResolution(),d=this.ovmap.getExtent().getCenterLonLat();return{lon:d.lon+(a.x-b.w/2)*c,lat:d.lat-(a.y-b.h/2)*c}},getOverviewPxFromLonLat:function(a){var b=
1826 this.ovmap.getResolution(),c=this.ovmap.getExtent();if(c)return{x:Math.round(1/b*(a.lon-c.left)),y:Math.round(1/b*(c.top-a.lat))}},CLASS_NAME:"OpenLayers.Control.OverviewMap"});OpenLayers.Animation=function(a){var b=!(!a.requestAnimationFrame&&!a.webkitRequestAnimationFrame&&!a.mozRequestAnimationFrame&&!a.oRequestAnimationFrame&&!a.msRequestAnimationFrame),c=function(){var b=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(b){a.setTimeout(b,16)};return function(c,d){b.apply(a,[c,d])}}(),d=0,e={};return{isNative:b,requestFrame:c,start:function(a,b,h){var b=0<b?b:Number.POSITIVE_INFINITY,
1827 i=++d,j=+new Date;e[i]=function(){e[i]&&+new Date-j<=b?(a(),e[i]&&c(e[i],h)):delete e[i]};c(e[i],h);return i},stop:function(a){delete e[a]}}}(window);OpenLayers.Tween=OpenLayers.Class({easing:null,begin:null,finish:null,duration:null,callbacks:null,time:null,animationId:null,playing:!1,initialize:function(a){this.easing=a?a:OpenLayers.Easing.Expo.easeOut},start:function(a,b,c,d){this.playing=!0;this.begin=a;this.finish=b;this.duration=c;this.callbacks=d.callbacks;this.time=0;OpenLayers.Animation.stop(this.animationId);this.animationId=null;this.callbacks&&this.callbacks.start&&this.callbacks.start.call(this,this.begin);this.animationId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.play,
1828 this))},stop:function(){this.playing&&(this.callbacks&&this.callbacks.done&&this.callbacks.done.call(this,this.finish),OpenLayers.Animation.stop(this.animationId),this.animationId=null,this.playing=!1)},play:function(){var a={},b;for(b in this.begin){var c=this.begin[b],d=this.finish[b];if(null==c||null==d||isNaN(c)||isNaN(d))throw new TypeError("invalid value for Tween");a[b]=this.easing.apply(this,[this.time,c,d-c,this.duration])}this.time++;this.callbacks&&this.callbacks.eachStep&&this.callbacks.eachStep.call(this,
1829 a);this.time>this.duration&&this.stop()},CLASS_NAME:"OpenLayers.Tween"});OpenLayers.Easing={CLASS_NAME:"OpenLayers.Easing"};OpenLayers.Easing.Linear={easeIn:function(a,b,c,d){return c*a/d+b},easeOut:function(a,b,c,d){return c*a/d+b},easeInOut:function(a,b,c,d){return c*a/d+b},CLASS_NAME:"OpenLayers.Easing.Linear"};
1830 OpenLayers.Easing.Expo={easeIn:function(a,b,c,d){return 0==a?b:c*Math.pow(2,10*(a/d-1))+b},easeOut:function(a,b,c,d){return a==d?b+c:c*(-Math.pow(2,-10*a/d)+1)+b},easeInOut:function(a,b,c,d){return 0==a?b:a==d?b+c:1>(a/=d/2)?c/2*Math.pow(2,10*(a-1))+b:c/2*(-Math.pow(2,-10*--a)+2)+b},CLASS_NAME:"OpenLayers.Easing.Expo"};
1831 OpenLayers.Easing.Quad={easeIn:function(a,b,c,d){return c*(a/=d)*a+b},easeOut:function(a,b,c,d){return-c*(a/=d)*(a-2)+b},easeInOut:function(a,b,c,d){return 1>(a/=d/2)?c/2*a*a+b:-c/2*(--a*(a-2)-1)+b},CLASS_NAME:"OpenLayers.Easing.Quad"};OpenLayers.Projection=OpenLayers.Class({proj:null,projCode:null,titleRegEx:/\+title=[^\+]*/,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.projCode=a;window.Proj4js&&(this.proj=new Proj4js.Proj(a))},getCode:function(){return this.proj?this.proj.srsCode:this.projCode},getUnits:function(){return this.proj?this.proj.units:null},toString:function(){return this.getCode()},equals:function(a){var b=!1;a&&(a instanceof OpenLayers.Projection||(a=new OpenLayers.Projection(a)),window.Proj4js&&
1832 this.proj.defData&&a.proj.defData?b=this.proj.defData.replace(this.titleRegEx,"")==a.proj.defData.replace(this.titleRegEx,""):a.getCode&&(b=this.getCode(),a=a.getCode(),b=b==a||!!OpenLayers.Projection.transforms[b]&&OpenLayers.Projection.transforms[b][a]===OpenLayers.Projection.nullTransform));return b},destroy:function(){delete this.proj;delete this.projCode},CLASS_NAME:"OpenLayers.Projection"});OpenLayers.Projection.transforms={};
1833 OpenLayers.Projection.defaults={"EPSG:4326":{units:"degrees",maxExtent:[-180,-90,180,90],yx:!0},"CRS:84":{units:"degrees",maxExtent:[-180,-90,180,90]},"EPSG:900913":{units:"m",maxExtent:[-2.003750834E7,-2.003750834E7,2.003750834E7,2.003750834E7]}};
1834 OpenLayers.Projection.addTransform=function(a,b,c){if(c===OpenLayers.Projection.nullTransform){var d=OpenLayers.Projection.defaults[a];d&&!OpenLayers.Projection.defaults[b]&&(OpenLayers.Projection.defaults[b]=d)}OpenLayers.Projection.transforms[a]||(OpenLayers.Projection.transforms[a]={});OpenLayers.Projection.transforms[a][b]=c};
1835 OpenLayers.Projection.transform=function(a,b,c){if(b&&c)if(b instanceof OpenLayers.Projection||(b=new OpenLayers.Projection(b)),c instanceof OpenLayers.Projection||(c=new OpenLayers.Projection(c)),b.proj&&c.proj)a=Proj4js.transform(b.proj,c.proj,a);else{var b=b.getCode(),c=c.getCode(),d=OpenLayers.Projection.transforms;if(d[b]&&d[b][c])d[b][c](a)}return a};OpenLayers.Projection.nullTransform=function(a){return a};
1836 (function(){function a(a){a.x=180*a.x/d;a.y=180/Math.PI*(2*Math.atan(Math.exp(a.y/d*Math.PI))-Math.PI/2);return a}function b(a){a.x=a.x*d/180;a.y=Math.log(Math.tan((90+a.y)*Math.PI/360))/Math.PI*d;return a}function c(c,d){var e=OpenLayers.Projection.addTransform,f=OpenLayers.Projection.nullTransform,g,m,n,o,p;g=0;for(m=d.length;g<m;++g){n=d[g];e(c,n,b);e(n,c,a);for(p=g+1;p<m;++p)o=d[p],e(n,o,f),e(o,n,f)}}var d=2.003750834E7,e=["EPSG:900913","EPSG:3857","EPSG:102113","EPSG:102100"],f=["CRS:84","urn:ogc:def:crs:EPSG:6.6:4326",
1837 "EPSG:4326"],g;for(g=e.length-1;0<=g;--g)c(e[g],f);for(g=f.length-1;0<=g;--g)c(f[g],e)})();OpenLayers.Map=OpenLayers.Class({Z_INDEX_BASE:{BaseLayer:100,Overlay:325,Feature:725,Popup:750,Control:1E3},id:null,fractionalZoom:!1,events:null,allOverlays:!1,div:null,dragging:!1,size:null,viewPortDiv:null,layerContainerOrigin:null,layerContainerDiv:null,layers:null,controls:null,popups:null,baseLayer:null,center:null,resolution:null,zoom:0,panRatio:1.5,options:null,tileSize:null,projection:"EPSG:4326",units:null,resolutions:null,maxResolution:null,minResolution:null,maxScale:null,minScale:null,
1838 maxExtent:null,minExtent:null,restrictedExtent:null,numZoomLevels:16,theme:null,displayProjection:null,fallThrough:!0,panTween:null,eventListeners:null,panMethod:OpenLayers.Easing.Expo.easeOut,panDuration:50,paddingForPopups:null,minPx:null,maxPx:null,initialize:function(a,b){1===arguments.length&&"object"===typeof a&&(a=(b=a)&&b.div);this.tileSize=new OpenLayers.Size(OpenLayers.Map.TILE_WIDTH,OpenLayers.Map.TILE_HEIGHT);this.paddingForPopups=new OpenLayers.Bounds(15,15,15,15);this.theme=OpenLayers._getScriptLocation()+
1839 "theme/default/style.css";this.options=OpenLayers.Util.extend({},b);OpenLayers.Util.extend(this,b);OpenLayers.Util.applyDefaults(this,OpenLayers.Projection.defaults[this.projection instanceof OpenLayers.Projection?this.projection.projCode:this.projection]);this.maxExtent&&!(this.maxExtent instanceof OpenLayers.Bounds)&&(this.maxExtent=new OpenLayers.Bounds(this.maxExtent));this.minExtent&&!(this.minExtent instanceof OpenLayers.Bounds)&&(this.minExtent=new OpenLayers.Bounds(this.minExtent));this.restrictedExtent&&
1840 !(this.restrictedExtent instanceof OpenLayers.Bounds)&&(this.restrictedExtent=new OpenLayers.Bounds(this.restrictedExtent));this.center&&!(this.center instanceof OpenLayers.LonLat)&&(this.center=new OpenLayers.LonLat(this.center));this.layers=[];this.id=OpenLayers.Util.createUniqueID("OpenLayers.Map_");this.div=OpenLayers.Util.getElement(a);this.div||(this.div=document.createElement("div"),this.div.style.height="1px",this.div.style.width="1px");OpenLayers.Element.addClass(this.div,"olMap");var c=
1841 this.id+"_OpenLayers_ViewPort";this.viewPortDiv=OpenLayers.Util.createDiv(c,null,null,null,"relative",null,"hidden");this.viewPortDiv.style.width="100%";this.viewPortDiv.style.height="100%";this.viewPortDiv.className="olMapViewport";this.div.appendChild(this.viewPortDiv);this.events=new OpenLayers.Events(this,this.viewPortDiv,null,this.fallThrough,{includeXY:!0});c=this.id+"_OpenLayers_Container";this.layerContainerDiv=OpenLayers.Util.createDiv(c);this.layerContainerDiv.style.width="100px";this.layerContainerDiv.style.height=
1842 "100px";this.layerContainerDiv.style.zIndex=this.Z_INDEX_BASE.Popup-1;this.viewPortDiv.appendChild(this.layerContainerDiv);this.updateSize();if(this.eventListeners instanceof Object)this.events.on(this.eventListeners);9>parseFloat(navigator.appVersion.split("MSIE")[1])?this.events.register("resize",this,this.updateSize):(this.updateSizeDestroy=OpenLayers.Function.bind(this.updateSize,this),OpenLayers.Event.observe(window,"resize",this.updateSizeDestroy));if(this.theme){for(var c=!0,d=document.getElementsByTagName("link"),
1843 e=0,f=d.length;e<f;++e)if(OpenLayers.Util.isEquivalentUrl(d.item(e).href,this.theme)){c=!1;break}c&&(c=document.createElement("link"),c.setAttribute("rel","stylesheet"),c.setAttribute("type","text/css"),c.setAttribute("href",this.theme),document.getElementsByTagName("head")[0].appendChild(c))}null==this.controls&&(this.controls=[],null!=OpenLayers.Control&&(OpenLayers.Control.Navigation?this.controls.push(new OpenLayers.Control.Navigation):OpenLayers.Control.TouchNavigation&&this.controls.push(new OpenLayers.Control.TouchNavigation),
1844 OpenLayers.Control.Zoom?this.controls.push(new OpenLayers.Control.Zoom):OpenLayers.Control.PanZoom&&this.controls.push(new OpenLayers.Control.PanZoom),OpenLayers.Control.ArgParser&&this.controls.push(new OpenLayers.Control.ArgParser),OpenLayers.Control.Attribution&&this.controls.push(new OpenLayers.Control.Attribution)));e=0;for(f=this.controls.length;e<f;e++)this.addControlToMap(this.controls[e]);this.popups=[];this.unloadDestroy=OpenLayers.Function.bind(this.destroy,this);OpenLayers.Event.observe(window,
1845 "unload",this.unloadDestroy);b&&b.layers&&(delete this.center,this.addLayers(b.layers),b.center&&!this.getCenter()&&this.setCenter(b.center,b.zoom))},getViewport:function(){return this.viewPortDiv},render:function(a){this.div=OpenLayers.Util.getElement(a);OpenLayers.Element.addClass(this.div,"olMap");this.viewPortDiv.parentNode.removeChild(this.viewPortDiv);this.div.appendChild(this.viewPortDiv);this.updateSize()},unloadDestroy:null,updateSizeDestroy:null,destroy:function(){if(!this.unloadDestroy)return!1;
1846 this.panTween&&(this.panTween.stop(),this.panTween=null);OpenLayers.Event.stopObserving(window,"unload",this.unloadDestroy);this.unloadDestroy=null;this.updateSizeDestroy?OpenLayers.Event.stopObserving(window,"resize",this.updateSizeDestroy):this.events.unregister("resize",this,this.updateSize);this.paddingForPopups=null;if(null!=this.controls){for(var a=this.controls.length-1;0<=a;--a)this.controls[a].destroy();this.controls=null}if(null!=this.layers){for(a=this.layers.length-1;0<=a;--a)this.layers[a].destroy(!1);
1847 this.layers=null}this.viewPortDiv&&this.div.removeChild(this.viewPortDiv);this.viewPortDiv=null;this.eventListeners&&(this.events.un(this.eventListeners),this.eventListeners=null);this.events.destroy();this.options=this.events=null},setOptions:function(a){var b=this.minPx&&a.restrictedExtent!=this.restrictedExtent;OpenLayers.Util.extend(this,a);b&&this.moveTo(this.getCachedCenter(),this.zoom,{forceZoomChange:!0})},getTileSize:function(){return this.tileSize},getBy:function(a,b,c){var d="function"==
1848 typeof c.test;return OpenLayers.Array.filter(this[a],function(a){return a[b]==c||d&&c.test(a[b])})},getLayersBy:function(a,b){return this.getBy("layers",a,b)},getLayersByName:function(a){return this.getLayersBy("name",a)},getLayersByClass:function(a){return this.getLayersBy("CLASS_NAME",a)},getControlsBy:function(a,b){return this.getBy("controls",a,b)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},getLayer:function(a){for(var b=null,c=0,d=this.layers.length;c<d;c++){var e=
1849 this.layers[c];if(e.id==a){b=e;break}}return b},setLayerZIndex:function(a,b){a.setZIndex(this.Z_INDEX_BASE[a.isBaseLayer?"BaseLayer":"Overlay"]+5*b)},resetLayersZIndex:function(){for(var a=0,b=this.layers.length;a<b;a++)this.setLayerZIndex(this.layers[a],a)},addLayer:function(a){for(var b=0,c=this.layers.length;b<c;b++)if(this.layers[b]==a)return!1;if(!1===this.events.triggerEvent("preaddlayer",{layer:a}))return!1;this.allOverlays&&(a.isBaseLayer=!1);a.div.className="olLayerDiv";a.div.style.overflow=
1850 "";this.setLayerZIndex(a,this.layers.length);a.isFixed?this.viewPortDiv.appendChild(a.div):this.layerContainerDiv.appendChild(a.div);this.layers.push(a);a.setMap(this);a.isBaseLayer||this.allOverlays&&!this.baseLayer?null==this.baseLayer?this.setBaseLayer(a):a.setVisibility(!1):a.redraw();this.events.triggerEvent("addlayer",{layer:a});a.events.triggerEvent("added",{map:this,layer:a});a.afterAdd();return!0},addLayers:function(a){for(var b=0,c=a.length;b<c;b++)this.addLayer(a[b])},removeLayer:function(a,
1851 b){if(!1!==this.events.triggerEvent("preremovelayer",{layer:a})){null==b&&(b=!0);a.isFixed?this.viewPortDiv.removeChild(a.div):this.layerContainerDiv.removeChild(a.div);OpenLayers.Util.removeItem(this.layers,a);a.removeMap(this);a.map=null;if(this.baseLayer==a&&(this.baseLayer=null,b))for(var c=0,d=this.layers.length;c<d;c++){var e=this.layers[c];if(e.isBaseLayer||this.allOverlays){this.setBaseLayer(e);break}}this.resetLayersZIndex();this.events.triggerEvent("removelayer",{layer:a});a.events.triggerEvent("removed",
1852 {map:this,layer:a})}},getNumLayers:function(){return this.layers.length},getLayerIndex:function(a){return OpenLayers.Util.indexOf(this.layers,a)},setLayerIndex:function(a,b){var c=this.getLayerIndex(a);0>b?b=0:b>this.layers.length&&(b=this.layers.length);if(c!=b){this.layers.splice(c,1);this.layers.splice(b,0,a);for(var c=0,d=this.layers.length;c<d;c++)this.setLayerZIndex(this.layers[c],c);this.events.triggerEvent("changelayer",{layer:a,property:"order"});this.allOverlays&&(0===b?this.setBaseLayer(a):
1853 this.baseLayer!==this.layers[0]&&this.setBaseLayer(this.layers[0]))}},raiseLayer:function(a,b){var c=this.getLayerIndex(a)+b;this.setLayerIndex(a,c)},setBaseLayer:function(a){if(a!=this.baseLayer&&-1!=OpenLayers.Util.indexOf(this.layers,a)){var b=this.getCachedCenter(),c=OpenLayers.Util.getResolutionFromScale(this.getScale(),a.units);null!=this.baseLayer&&!this.allOverlays&&this.baseLayer.setVisibility(!1);this.baseLayer=a;if(!this.allOverlays||this.baseLayer.visibility)this.baseLayer.setVisibility(!0),
1854 !1===this.baseLayer.inRange&&this.baseLayer.redraw();null!=b&&(a=this.getZoomForResolution(c||this.resolution,!0),this.setCenter(b,a,!1,!0));this.events.triggerEvent("changebaselayer",{layer:this.baseLayer})}},addControl:function(a,b){this.controls.push(a);this.addControlToMap(a,b)},addControls:function(a,b){for(var c=1===arguments.length?[]:b,d=0,e=a.length;d<e;d++)this.addControl(a[d],c[d]?c[d]:null)},addControlToMap:function(a,b){a.outsideViewport=null!=a.div;this.displayProjection&&!a.displayProjection&&
1855 (a.displayProjection=this.displayProjection);a.setMap(this);var c=a.draw(b);c&&!a.outsideViewport&&(c.style.zIndex=this.Z_INDEX_BASE.Control+this.controls.length,this.viewPortDiv.appendChild(c));a.autoActivate&&a.activate()},getControl:function(a){for(var b=null,c=0,d=this.controls.length;c<d;c++){var e=this.controls[c];if(e.id==a){b=e;break}}return b},removeControl:function(a){a&&a==this.getControl(a.id)&&(a.div&&a.div.parentNode==this.viewPortDiv&&this.viewPortDiv.removeChild(a.div),OpenLayers.Util.removeItem(this.controls,
1856 a))},addPopup:function(a,b){if(b)for(var c=this.popups.length-1;0<=c;--c)this.removePopup(this.popups[c]);a.map=this;this.popups.push(a);if(c=a.draw())c.style.zIndex=this.Z_INDEX_BASE.Popup+this.popups.length,this.layerContainerDiv.appendChild(c)},removePopup:function(a){OpenLayers.Util.removeItem(this.popups,a);if(a.div)try{this.layerContainerDiv.removeChild(a.div)}catch(b){}a.map=null},getSize:function(){var a=null;null!=this.size&&(a=this.size.clone());return a},updateSize:function(){var a=this.getCurrentSize();
1857 if(a&&!isNaN(a.h)&&!isNaN(a.w)){this.events.clearMouseCache();var b=this.getSize();null==b&&(this.size=b=a);if(!a.equals(b)){this.size=a;a=0;for(b=this.layers.length;a<b;a++)this.layers[a].onMapResize();a=this.getCachedCenter();null!=this.baseLayer&&null!=a&&(b=this.getZoom(),this.zoom=null,this.setCenter(a,b))}}},getCurrentSize:function(){var a=new OpenLayers.Size(this.div.clientWidth,this.div.clientHeight);if(0==a.w&&0==a.h||isNaN(a.w)&&isNaN(a.h))a.w=this.div.offsetWidth,a.h=this.div.offsetHeight;
1858 if(0==a.w&&0==a.h||isNaN(a.w)&&isNaN(a.h))a.w=parseInt(this.div.style.width),a.h=parseInt(this.div.style.height);return a},calculateBounds:function(a,b){var c=null;null==a&&(a=this.getCachedCenter());null==b&&(b=this.getResolution());if(null!=a&&null!=b)var c=this.size.w*b/2,d=this.size.h*b/2,c=new OpenLayers.Bounds(a.lon-c,a.lat-d,a.lon+c,a.lat+d);return c},getCenter:function(){var a=null,b=this.getCachedCenter();b&&(a=b.clone());return a},getCachedCenter:function(){!this.center&&this.size&&(this.center=
1859 this.getLonLatFromViewPortPx({x:this.size.w/2,y:this.size.h/2}));return this.center},getZoom:function(){return this.zoom},pan:function(a,b,c){c=OpenLayers.Util.applyDefaults(c,{animate:!0,dragging:!1});if(c.dragging)(0!=a||0!=b)&&this.moveByPx(a,b);else{var d=this.getViewPortPxFromLonLat(this.getCachedCenter()),a=d.add(a,b);if(this.dragging||!a.equals(d))d=this.getLonLatFromViewPortPx(a),c.animate?this.panTo(d):(this.moveTo(d),this.dragging&&(this.dragging=!1,this.events.triggerEvent("moveend")))}},
1860 panTo:function(a){if(this.panMethod&&this.getExtent().scale(this.panRatio).containsLonLat(a)){this.panTween||(this.panTween=new OpenLayers.Tween(this.panMethod));var b=this.getCachedCenter();if(!a.equals(b)){var b=this.getPixelFromLonLat(b),c=this.getPixelFromLonLat(a),d=0,e=0;this.panTween.start({x:0,y:0},{x:c.x-b.x,y:c.y-b.y},this.panDuration,{callbacks:{eachStep:OpenLayers.Function.bind(function(a){this.moveByPx(a.x-d,a.y-e);d=Math.round(a.x);e=Math.round(a.y)},this),done:OpenLayers.Function.bind(function(){this.moveTo(a);
1861 this.dragging=false;this.events.triggerEvent("moveend")},this)}})}}else this.setCenter(a)},setCenter:function(a,b,c,d){this.panTween&&this.panTween.stop();this.moveTo(a,b,{dragging:c,forceZoomChange:d})},moveByPx:function(a,b){var c=this.size.w/2,d=this.size.h/2,e=c+a,f=d+b,g=this.baseLayer.wrapDateLine,h=0,i=0;this.restrictedExtent&&(h=c,i=d,g=!1);a=g||e<=this.maxPx.x-h&&e>=this.minPx.x+h?Math.round(a):0;b=f<=this.maxPx.y-i&&f>=this.minPx.y+i?Math.round(b):0;if(a||b){this.dragging||(this.dragging=
1862 !0,this.events.triggerEvent("movestart"));this.center=null;a&&(this.layerContainerDiv.style.left=parseInt(this.layerContainerDiv.style.left)-a+"px",this.minPx.x-=a,this.maxPx.x-=a);b&&(this.layerContainerDiv.style.top=parseInt(this.layerContainerDiv.style.top)-b+"px",this.minPx.y-=b,this.maxPx.y-=b);d=0;for(e=this.layers.length;d<e;++d)if(c=this.layers[d],c.visibility&&(c===this.baseLayer||c.inRange))c.moveByPx(a,b),c.events.triggerEvent("move");this.events.triggerEvent("move")}},adjustZoom:function(a){var b=
1863 this.baseLayer.resolutions,c=this.getMaxExtent().getWidth()/this.size.w;if(this.getResolutionForZoom(a)>c)for(var d=a|0,e=b.length;d<e;++d)if(b[d]<=c){a=d;break}return a},moveTo:function(a,b,c){null!=a&&!(a instanceof OpenLayers.LonLat)&&(a=new OpenLayers.LonLat(a));c||(c={});null!=b&&(b=parseFloat(b),this.fractionalZoom||(b=Math.round(b)));if(this.baseLayer.wrapDateLine){var d=b,b=this.adjustZoom(b);b!==d&&(a=this.getCenter())}var d=c.dragging||this.dragging,e=c.forceZoomChange;!this.getCachedCenter()&&
1864 !this.isValidLonLat(a)&&(a=this.maxExtent.getCenterLonLat(),this.center=a.clone());if(null!=this.restrictedExtent){null==a&&(a=this.center);null==b&&(b=this.getZoom());var f=this.getResolutionForZoom(b),f=this.calculateBounds(a,f);if(!this.restrictedExtent.containsBounds(f)){var g=this.restrictedExtent.getCenterLonLat();f.getWidth()>this.restrictedExtent.getWidth()?a=new OpenLayers.LonLat(g.lon,a.lat):f.left<this.restrictedExtent.left?a=a.add(this.restrictedExtent.left-f.left,0):f.right>this.restrictedExtent.right&&
1865 (a=a.add(this.restrictedExtent.right-f.right,0));f.getHeight()>this.restrictedExtent.getHeight()?a=new OpenLayers.LonLat(a.lon,g.lat):f.bottom<this.restrictedExtent.bottom?a=a.add(0,this.restrictedExtent.bottom-f.bottom):f.top>this.restrictedExtent.top&&(a=a.add(0,this.restrictedExtent.top-f.top))}}e=e||this.isValidZoomLevel(b)&&b!=this.getZoom();f=this.isValidLonLat(a)&&!a.equals(this.center);if(e||f||d){d||this.events.triggerEvent("movestart");f&&(!e&&this.center&&this.centerLayerContainer(a),this.center=
1866 a.clone());a=e?this.getResolutionForZoom(b):this.getResolution();if(e||null==this.layerContainerOrigin){this.layerContainerOrigin=this.getCachedCenter();this.layerContainerDiv.style.left="0px";this.layerContainerDiv.style.top="0px";var f=this.getMaxExtent({restricted:!0}),h=f.getCenterLonLat(),g=this.center.lon-h.lon,h=h.lat-this.center.lat,i=Math.round(f.getWidth()/a),j=Math.round(f.getHeight()/a);this.minPx={x:(this.size.w-i)/2-g/a,y:(this.size.h-j)/2-h/a};this.maxPx={x:this.minPx.x+Math.round(f.getWidth()/
1867 a),y:this.minPx.y+Math.round(f.getHeight()/a)}}e&&(this.zoom=b,this.resolution=a);a=this.getExtent();this.baseLayer.visibility&&(this.baseLayer.moveTo(a,e,c.dragging),c.dragging||this.baseLayer.events.triggerEvent("moveend",{zoomChanged:e}));a=this.baseLayer.getExtent();for(b=this.layers.length-1;0<=b;--b)if(f=this.layers[b],f!==this.baseLayer&&!f.isBaseLayer&&(g=f.calculateInRange(),f.inRange!=g&&((f.inRange=g)||f.display(!1),this.events.triggerEvent("changelayer",{layer:f,property:"visibility"})),
1868 g&&f.visibility))f.moveTo(a,e,c.dragging),c.dragging||f.events.triggerEvent("moveend",{zoomChanged:e});this.events.triggerEvent("move");d||this.events.triggerEvent("moveend");if(e){b=0;for(c=this.popups.length;b<c;b++)this.popups[b].updatePosition();this.events.triggerEvent("zoomend")}}},centerLayerContainer:function(a){var b=this.getViewPortPxFromLonLat(this.layerContainerOrigin),c=this.getViewPortPxFromLonLat(a);if(null!=b&&null!=c){var d=parseInt(this.layerContainerDiv.style.left),a=parseInt(this.layerContainerDiv.style.top),
1869 e=Math.round(b.x-c.x),b=Math.round(b.y-c.y);this.layerContainerDiv.style.left=e+"px";this.layerContainerDiv.style.top=b+"px";d-=e;a-=b;this.minPx.x-=d;this.maxPx.x-=d;this.minPx.y-=a;this.maxPx.y-=a}},isValidZoomLevel:function(a){return null!=a&&0<=a&&a<this.getNumZoomLevels()},isValidLonLat:function(a){var b=!1;null!=a&&(b=this.getMaxExtent(),b=b.containsLonLat(a,{worldBounds:this.baseLayer.wrapDateLine&&b}));return b},getProjection:function(){var a=this.getProjectionObject();return a?a.getCode():
1870 null},getProjectionObject:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.projection);return a},getMaxResolution:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.maxResolution);return a},getMaxExtent:function(a){var b=null;a&&a.restricted&&this.restrictedExtent?b=this.restrictedExtent:null!=this.baseLayer&&(b=this.baseLayer.maxExtent);return b},getNumZoomLevels:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.numZoomLevels);return a},getExtent:function(){var a=
1871 null;null!=this.baseLayer&&(a=this.baseLayer.getExtent());return a},getResolution:function(){var a=null;null!=this.baseLayer?a=this.baseLayer.getResolution():!0===this.allOverlays&&0<this.layers.length&&(a=this.layers[0].getResolution());return a},getUnits:function(){var a=null;null!=this.baseLayer&&(a=this.baseLayer.units);return a},getScale:function(){var a=null;null!=this.baseLayer&&(a=this.getResolution(),a=OpenLayers.Util.getScaleFromResolution(a,this.baseLayer.units));return a},getZoomForExtent:function(a,
1872 b){var c=null;null!=this.baseLayer&&(c=this.baseLayer.getZoomForExtent(a,b));return c},getResolutionForZoom:function(a){var b=null;this.baseLayer&&(b=this.baseLayer.getResolutionForZoom(a));return b},getZoomForResolution:function(a,b){var c=null;null!=this.baseLayer&&(c=this.baseLayer.getZoomForResolution(a,b));return c},zoomTo:function(a){this.isValidZoomLevel(a)&&this.setCenter(null,a)},zoomIn:function(){this.zoomTo(this.getZoom()+1)},zoomOut:function(){this.zoomTo(this.getZoom()-1)},zoomToExtent:function(a,
1873 b){a instanceof OpenLayers.Bounds||(a=new OpenLayers.Bounds(a));var c=a.getCenterLonLat();if(this.baseLayer.wrapDateLine){c=this.getMaxExtent();for(a=a.clone();a.right<a.left;)a.right+=c.getWidth();c=a.getCenterLonLat().wrapDateLine(c)}this.setCenter(c,this.getZoomForExtent(a,b))},zoomToMaxExtent:function(a){this.zoomToExtent(this.getMaxExtent({restricted:a?a.restricted:!0}))},zoomToScale:function(a,b){var c=OpenLayers.Util.getResolutionFromScale(a,this.baseLayer.units),d=this.size.w*c/2,c=this.size.h*
1874 c/2,e=this.getCachedCenter();this.zoomToExtent(new OpenLayers.Bounds(e.lon-d,e.lat-c,e.lon+d,e.lat+c),b)},getLonLatFromViewPortPx:function(a){var b=null;null!=this.baseLayer&&(b=this.baseLayer.getLonLatFromViewPortPx(a));return b},getViewPortPxFromLonLat:function(a){var b=null;null!=this.baseLayer&&(b=this.baseLayer.getViewPortPxFromLonLat(a));return b},getLonLatFromPixel:function(a){return this.getLonLatFromViewPortPx(a)},getPixelFromLonLat:function(a){a=this.getViewPortPxFromLonLat(a);a.x=Math.round(a.x);
1875 a.y=Math.round(a.y);return a},getGeodesicPixelSize:function(a){var b=a?this.getLonLatFromPixel(a):this.getCachedCenter()||new OpenLayers.LonLat(0,0),c=this.getResolution(),a=b.add(-c/2,0),d=b.add(c/2,0),e=b.add(0,-c/2),b=b.add(0,c/2),c=new OpenLayers.Projection("EPSG:4326"),f=this.getProjectionObject()||c;f.equals(c)||(a.transform(f,c),d.transform(f,c),e.transform(f,c),b.transform(f,c));return new OpenLayers.Size(OpenLayers.Util.distVincenty(a,d),OpenLayers.Util.distVincenty(e,b))},getViewPortPxFromLayerPx:function(a){var b=
1876 null;if(null!=a)var b=parseInt(this.layerContainerDiv.style.left),c=parseInt(this.layerContainerDiv.style.top),b=a.add(b,c);return b},getLayerPxFromViewPortPx:function(a){var b=null;if(null!=a){var b=-parseInt(this.layerContainerDiv.style.left),c=-parseInt(this.layerContainerDiv.style.top),b=a.add(b,c);if(isNaN(b.x)||isNaN(b.y))b=null}return b},getLonLatFromLayerPx:function(a){a=this.getViewPortPxFromLayerPx(a);return this.getLonLatFromViewPortPx(a)},getLayerPxFromLonLat:function(a){return this.getLayerPxFromViewPortPx(this.getPixelFromLonLat(a))},
1877 CLASS_NAME:"OpenLayers.Map"});OpenLayers.Map.TILE_WIDTH=256;OpenLayers.Map.TILE_HEIGHT=256;OpenLayers.Layer=OpenLayers.Class({id:null,name:null,div:null,opacity:1,alwaysInRange:null,RESOLUTION_PROPERTIES:"scales resolutions maxScale minScale maxResolution minResolution numZoomLevels maxZoomLevel".split(" "),events:null,map:null,isBaseLayer:!1,alpha:!1,displayInLayerSwitcher:!0,visibility:!0,attribution:null,inRange:!1,imageSize:null,options:null,eventListeners:null,gutter:0,projection:null,units:null,scales:null,resolutions:null,maxExtent:null,minExtent:null,maxResolution:null,minResolution:null,
1878 numZoomLevels:null,minScale:null,maxScale:null,displayOutsideMaxExtent:!1,wrapDateLine:!1,metadata:null,initialize:function(a,b){this.metadata={};this.addOptions(b);this.name=a;if(null==this.id&&(this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"),this.div=OpenLayers.Util.createDiv(this.id),this.div.style.width="100%",this.div.style.height="100%",this.div.dir="ltr",this.events=new OpenLayers.Events(this,this.div),this.eventListeners instanceof Object))this.events.on(this.eventListeners)},
1879 destroy:function(a){null==a&&(a=!0);null!=this.map&&this.map.removeLayer(this,a);this.options=this.div=this.name=this.map=this.projection=null;this.events&&(this.eventListeners&&this.events.un(this.eventListeners),this.events.destroy());this.events=this.eventListeners=null},clone:function(a){null==a&&(a=new OpenLayers.Layer(this.name,this.getOptions()));OpenLayers.Util.applyDefaults(a,this);a.map=null;return a},getOptions:function(){var a={},b;for(b in this.options)a[b]=this[b];return a},setName:function(a){a!=
1880 this.name&&(this.name=a,null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"name"}))},addOptions:function(a,b){null==this.options&&(this.options={});if(a&&("string"==typeof a.projection&&(a.projection=new OpenLayers.Projection(a.projection)),a.projection&&OpenLayers.Util.applyDefaults(a,OpenLayers.Projection.defaults[a.projection.getCode()]),a.maxExtent&&!(a.maxExtent instanceof OpenLayers.Bounds)&&(a.maxExtent=new OpenLayers.Bounds(a.maxExtent)),a.minExtent&&!(a.minExtent instanceof
1881 OpenLayers.Bounds)))a.minExtent=new OpenLayers.Bounds(a.minExtent);OpenLayers.Util.extend(this.options,a);OpenLayers.Util.extend(this,a);this.projection&&this.projection.getUnits()&&(this.units=this.projection.getUnits());if(this.map){var c=this.map.getResolution(),d=this.RESOLUTION_PROPERTIES.concat(["projection","units","minExtent","maxExtent"]),e;for(e in a)if(a.hasOwnProperty(e)&&0<=OpenLayers.Util.indexOf(d,e)){this.initResolutions();b&&this.map.baseLayer===this&&(this.map.setCenter(this.map.getCenter(),
1882 this.map.getZoomForResolution(c),!1,!0),this.map.events.triggerEvent("changebaselayer",{layer:this}));break}}},onMapResize:function(){},redraw:function(){var a=!1;if(this.map){this.inRange=this.calculateInRange();var b=this.getExtent();b&&(this.inRange&&this.visibility)&&(this.moveTo(b,!0,!1),this.events.triggerEvent("moveend",{zoomChanged:!0}),a=!0)}return a},moveTo:function(){var a=this.visibility;this.isBaseLayer||(a=a&&this.inRange);this.display(a)},moveByPx:function(){},setMap:function(a){null==
1883 this.map&&(this.map=a,this.maxExtent=this.maxExtent||this.map.maxExtent,this.minExtent=this.minExtent||this.map.minExtent,this.projection=this.projection||this.map.projection,"string"==typeof this.projection&&(this.projection=new OpenLayers.Projection(this.projection)),this.units=this.projection.getUnits()||this.units||this.map.units,this.initResolutions(),this.isBaseLayer||(this.inRange=this.calculateInRange(),this.div.style.display=this.visibility&&this.inRange?"":"none"),this.setTileSize())},afterAdd:function(){},
1884 removeMap:function(){},getImageSize:function(){return this.imageSize||this.tileSize},setTileSize:function(a){this.tileSize=a=a?a:this.tileSize?this.tileSize:this.map.getTileSize();this.gutter&&(this.imageSize=new OpenLayers.Size(a.w+2*this.gutter,a.h+2*this.gutter))},getVisibility:function(){return this.visibility},setVisibility:function(a){a!=this.visibility&&(this.visibility=a,this.display(a),this.redraw(),null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"visibility"}),
1885 this.events.triggerEvent("visibilitychanged"))},display:function(a){a!=("none"!=this.div.style.display)&&(this.div.style.display=a&&this.calculateInRange()?"block":"none")},calculateInRange:function(){var a=!1;this.alwaysInRange?a=!0:this.map&&(a=this.map.getResolution(),a=a>=this.minResolution&&a<=this.maxResolution);return a},setIsBaseLayer:function(a){a!=this.isBaseLayer&&(this.isBaseLayer=a,null!=this.map&&this.map.events.triggerEvent("changebaselayer",{layer:this}))},initResolutions:function(){var a,
1886 b,c,d={},e=!0;a=0;for(b=this.RESOLUTION_PROPERTIES.length;a<b;a++)c=this.RESOLUTION_PROPERTIES[a],d[c]=this.options[c],e&&this.options[c]&&(e=!1);null==this.alwaysInRange&&(this.alwaysInRange=e);null==d.resolutions&&(d.resolutions=this.resolutionsFromScales(d.scales));null==d.resolutions&&(d.resolutions=this.calculateResolutions(d));if(null==d.resolutions){a=0;for(b=this.RESOLUTION_PROPERTIES.length;a<b;a++)c=this.RESOLUTION_PROPERTIES[a],d[c]=null!=this.options[c]?this.options[c]:this.map[c];null==
1887 d.resolutions&&(d.resolutions=this.resolutionsFromScales(d.scales));null==d.resolutions&&(d.resolutions=this.calculateResolutions(d))}var f;this.options.maxResolution&&"auto"!==this.options.maxResolution&&(f=this.options.maxResolution);this.options.minScale&&(f=OpenLayers.Util.getResolutionFromScale(this.options.minScale,this.units));var g;this.options.minResolution&&"auto"!==this.options.minResolution&&(g=this.options.minResolution);this.options.maxScale&&(g=OpenLayers.Util.getResolutionFromScale(this.options.maxScale,
1888 this.units));d.resolutions&&(d.resolutions.sort(function(a,b){return b-a}),f||(f=d.resolutions[0]),g||(g=d.resolutions[d.resolutions.length-1]));if(this.resolutions=d.resolutions){b=this.resolutions.length;this.scales=Array(b);for(a=0;a<b;a++)this.scales[a]=OpenLayers.Util.getScaleFromResolution(this.resolutions[a],this.units);this.numZoomLevels=b}if(this.minResolution=g)this.maxScale=OpenLayers.Util.getScaleFromResolution(g,this.units);if(this.maxResolution=f)this.minScale=OpenLayers.Util.getScaleFromResolution(f,
1889 this.units)},resolutionsFromScales:function(a){if(null!=a){var b,c,d;d=a.length;b=Array(d);for(c=0;c<d;c++)b[c]=OpenLayers.Util.getResolutionFromScale(a[c],this.units);return b}},calculateResolutions:function(a){var b,c,d=a.maxResolution;null!=a.minScale?d=OpenLayers.Util.getResolutionFromScale(a.minScale,this.units):"auto"==d&&null!=this.maxExtent&&(b=this.map.getSize(),c=this.maxExtent.getWidth()/b.w,b=this.maxExtent.getHeight()/b.h,d=Math.max(c,b));c=a.minResolution;null!=a.maxScale?c=OpenLayers.Util.getResolutionFromScale(a.maxScale,
1890 this.units):"auto"==a.minResolution&&null!=this.minExtent&&(b=this.map.getSize(),c=this.minExtent.getWidth()/b.w,b=this.minExtent.getHeight()/b.h,c=Math.max(c,b));"number"!==typeof d&&("number"!==typeof c&&null!=this.maxExtent)&&(d=this.map.getTileSize(),d=Math.max(this.maxExtent.getWidth()/d.w,this.maxExtent.getHeight()/d.h));b=a.maxZoomLevel;a=a.numZoomLevels;"number"===typeof c&&"number"===typeof d&&void 0===a?a=Math.floor(Math.log(d/c)/Math.log(2))+1:void 0===a&&null!=b&&(a=b+1);if(!("number"!==
1891 typeof a||0>=a||"number"!==typeof d&&"number"!==typeof c)){b=Array(a);var e=2;"number"==typeof c&&"number"==typeof d&&(e=Math.pow(d/c,1/(a-1)));var f;if("number"===typeof d)for(f=0;f<a;f++)b[f]=d/Math.pow(e,f);else for(f=0;f<a;f++)b[a-1-f]=c*Math.pow(e,f);return b}},getResolution:function(){return this.getResolutionForZoom(this.map.getZoom())},getExtent:function(){return this.map.calculateBounds()},getZoomForExtent:function(a,b){var c=this.map.getSize();return this.getZoomForResolution(Math.max(a.getWidth()/
1892 c.w,a.getHeight()/c.h),b)},getDataExtent:function(){},getResolutionForZoom:function(a){a=Math.max(0,Math.min(a,this.resolutions.length-1));if(this.map.fractionalZoom)var b=Math.floor(a),c=Math.ceil(a),a=this.resolutions[b]-(a-b)*(this.resolutions[b]-this.resolutions[c]);else a=this.resolutions[Math.round(a)];return a},getZoomForResolution:function(a,b){var c,d;if(this.map.fractionalZoom){var e=0,f=this.resolutions[e],g=this.resolutions[this.resolutions.length-1],h;c=0;for(d=this.resolutions.length;c<
1893 d;++c)if(h=this.resolutions[c],h>=a&&(f=h,e=c),h<=a){g=h;break}c=f-g;c=0<c?e+(f-a)/c:e}else{f=Number.POSITIVE_INFINITY;c=0;for(d=this.resolutions.length;c<d;c++)if(b){e=Math.abs(this.resolutions[c]-a);if(e>f)break;f=e}else if(this.resolutions[c]<a)break;c=Math.max(0,c-1)}return c},getLonLatFromViewPortPx:function(a){var b=null,c=this.map;if(null!=a&&c.minPx){var b=c.getResolution(),d=c.getMaxExtent({restricted:!0}),b=new OpenLayers.LonLat((a.x-c.minPx.x)*b+d.left,(c.minPx.y-a.y)*b+d.top);this.wrapDateLine&&
1894 (b=b.wrapDateLine(this.maxExtent))}return b},getViewPortPxFromLonLat:function(a,b){var c=null;null!=a&&(b=b||this.map.getResolution(),c=this.map.calculateBounds(null,b),c=new OpenLayers.Pixel(1/b*(a.lon-c.left),1/b*(c.top-a.lat)));return c},setOpacity:function(a){if(a!=this.opacity){this.opacity=a;for(var b=this.div.childNodes,c=0,d=b.length;c<d;++c){var e=b[c].firstChild||b[c],f=b[c].lastChild;f&&"iframe"===f.nodeName.toLowerCase()&&(e=f.parentNode);OpenLayers.Util.modifyDOMElement(e,null,null,null,
1895 null,null,null,a)}null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"})}},getZIndex:function(){return this.div.style.zIndex},setZIndex:function(a){this.div.style.zIndex=a},adjustBounds:function(a){if(this.gutter)var b=this.gutter*this.map.getResolution(),a=new OpenLayers.Bounds(a.left-b,a.bottom-b,a.right+b,a.top+b);this.wrapDateLine&&(b={rightTolerance:this.getResolution(),leftTolerance:this.getResolution()},a=a.wrapDateLine(this.maxExtent,b));return a},CLASS_NAME:"OpenLayers.Layer"});OpenLayers.Layer.SphericalMercator={getExtent:function(){var a=null;return a=this.sphericalMercator?this.map.calculateBounds():OpenLayers.Layer.FixedZoomLevels.prototype.getExtent.apply(this)},getLonLatFromViewPortPx:function(a){return OpenLayers.Layer.prototype.getLonLatFromViewPortPx.apply(this,arguments)},getViewPortPxFromLonLat:function(a){return OpenLayers.Layer.prototype.getViewPortPxFromLonLat.apply(this,arguments)},initMercatorParameters:function(){this.RESOLUTIONS=[];for(var a=0;a<=this.MAX_ZOOM_LEVEL;++a)this.RESOLUTIONS[a]=
1896 156543.03390625/Math.pow(2,a);this.units="m";this.projection=this.projection||"EPSG:900913"},forwardMercator:function(){var a=new OpenLayers.Projection("EPSG:4326"),b=new OpenLayers.Projection("EPSG:900913");return function(c,d){var e=OpenLayers.Projection.transform({x:c,y:d},a,b);return new OpenLayers.LonLat(e.x,e.y)}}(),inverseMercator:function(){var a=new OpenLayers.Projection("EPSG:4326"),b=new OpenLayers.Projection("EPSG:900913");return function(c,d){var e=OpenLayers.Projection.transform({x:c,
1897 y:d},b,a);return new OpenLayers.LonLat(e.x,e.y)}}()};OpenLayers.Layer.EventPane=OpenLayers.Class(OpenLayers.Layer,{smoothDragPan:!0,isBaseLayer:!0,isFixed:!0,pane:null,mapObject:null,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);null==this.pane&&(this.pane=OpenLayers.Util.createDiv(this.div.id+"_EventPane"))},destroy:function(){this.pane=this.mapObject=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Layer.prototype.setMap.apply(this,arguments);this.pane.style.zIndex=
1898 parseInt(this.div.style.zIndex)+1;this.pane.style.display=this.div.style.display;this.pane.style.width="100%";this.pane.style.height="100%";"msie"==OpenLayers.BROWSER_NAME&&(this.pane.style.background="url("+OpenLayers.Util.getImageLocation("blank.gif")+")");this.isFixed?this.map.viewPortDiv.appendChild(this.pane):this.map.layerContainerDiv.appendChild(this.pane);this.loadMapObject();null==this.mapObject&&this.loadWarningMessage()},removeMap:function(a){this.pane&&this.pane.parentNode&&this.pane.parentNode.removeChild(this.pane);
1899 OpenLayers.Layer.prototype.removeMap.apply(this,arguments)},loadWarningMessage:function(){this.div.style.backgroundColor="darkblue";var a=this.map.getSize(),b=Math.min(a.w,300),c=Math.min(a.h,200),b=new OpenLayers.Size(b,c),a=(new OpenLayers.Pixel(a.w/2,a.h/2)).add(-b.w/2,-b.h/2),a=OpenLayers.Util.createDiv(this.name+"_warning",a,b,null,null,null,"auto");a.style.padding="7px";a.style.backgroundColor="yellow";a.innerHTML=this.getWarningHTML();this.div.appendChild(a)},getWarningHTML:function(){return""},
1900 display:function(a){OpenLayers.Layer.prototype.display.apply(this,arguments);this.pane.style.display=this.div.style.display},setZIndex:function(a){OpenLayers.Layer.prototype.setZIndex.apply(this,arguments);this.pane.style.zIndex=parseInt(this.div.style.zIndex)+1},moveByPx:function(a,b){OpenLayers.Layer.prototype.moveByPx.apply(this,arguments);this.dragPanMapObject?this.dragPanMapObject(a,-b):this.moveTo(this.map.getCachedCenter())},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,
1901 arguments);if(null!=this.mapObject){var d=this.map.getCenter(),e=this.map.getZoom();if(null!=d){var f=this.getOLLonLatFromMapObjectLonLat(this.getMapObjectCenter()),g=this.getOLZoomFromMapObjectZoom(this.getMapObjectZoom());if(!d.equals(f)||e!=g)!b&&f&&this.dragPanMapObject&&this.smoothDragPan?(e=this.map.getViewPortPxFromLonLat(f),d=this.map.getViewPortPxFromLonLat(d),this.dragPanMapObject(d.x-e.x,e.y-d.y)):(d=this.getMapObjectLonLatFromOLLonLat(d),e=this.getMapObjectZoomFromOLZoom(e),this.setMapObjectCenter(d,
1902 e,c))}}},getLonLatFromViewPortPx:function(a){var b=null;null!=this.mapObject&&null!=this.getMapObjectCenter()&&(b=this.getOLLonLatFromMapObjectLonLat(this.getMapObjectLonLatFromMapObjectPixel(this.getMapObjectPixelFromOLPixel(a))));return b},getViewPortPxFromLonLat:function(a){var b=null;null!=this.mapObject&&null!=this.getMapObjectCenter()&&(b=this.getOLPixelFromMapObjectPixel(this.getMapObjectPixelFromMapObjectLonLat(this.getMapObjectLonLatFromOLLonLat(a))));return b},getOLLonLatFromMapObjectLonLat:function(a){var b=
1903 null;null!=a&&(b=this.getLongitudeFromMapObjectLonLat(a),a=this.getLatitudeFromMapObjectLonLat(a),b=new OpenLayers.LonLat(b,a));return b},getMapObjectLonLatFromOLLonLat:function(a){var b=null;null!=a&&(b=this.getMapObjectLonLatFromLonLat(a.lon,a.lat));return b},getOLPixelFromMapObjectPixel:function(a){var b=null;null!=a&&(b=this.getXFromMapObjectPixel(a),a=this.getYFromMapObjectPixel(a),b=new OpenLayers.Pixel(b,a));return b},getMapObjectPixelFromOLPixel:function(a){var b=null;null!=a&&(b=this.getMapObjectPixelFromXY(a.x,
1904 a.y));return b},CLASS_NAME:"OpenLayers.Layer.EventPane"});OpenLayers.Layer.FixedZoomLevels=OpenLayers.Class({initialize:function(){},initResolutions:function(){for(var a=["minZoomLevel","maxZoomLevel","numZoomLevels"],b=0,c=a.length;b<c;b++){var d=a[b];this[d]=null!=this.options[d]?this.options[d]:this.map[d]}if(null==this.minZoomLevel||this.minZoomLevel<this.MIN_ZOOM_LEVEL)this.minZoomLevel=this.MIN_ZOOM_LEVEL;a=this.MAX_ZOOM_LEVEL-this.minZoomLevel+1;b=null==this.options.numZoomLevels&&null!=this.options.maxZoomLevel||null==this.numZoomLevels&&null!=this.maxZoomLevel?
1905 this.maxZoomLevel-this.minZoomLevel+1:this.numZoomLevels;this.numZoomLevels=null!=b?Math.min(b,a):a;this.maxZoomLevel=this.minZoomLevel+this.numZoomLevels-1;if(null!=this.RESOLUTIONS){a=0;this.resolutions=[];for(b=this.minZoomLevel;b<=this.maxZoomLevel;b++)this.resolutions[a++]=this.RESOLUTIONS[b];this.maxResolution=this.resolutions[0];this.minResolution=this.resolutions[this.resolutions.length-1]}},getResolution:function(){if(null!=this.resolutions)return OpenLayers.Layer.prototype.getResolution.apply(this,
1906 arguments);var a=null,b=this.map.getSize(),c=this.getExtent();null!=b&&null!=c&&(a=Math.max(c.getWidth()/b.w,c.getHeight()/b.h));return a},getExtent:function(){var a=this.map.getSize(),b=this.getLonLatFromViewPortPx({x:0,y:0}),a=this.getLonLatFromViewPortPx({x:a.w,y:a.h});return null!=b&&null!=a?new OpenLayers.Bounds(b.lon,a.lat,a.lon,b.lat):null},getZoomForResolution:function(a){return null!=this.resolutions?OpenLayers.Layer.prototype.getZoomForResolution.apply(this,arguments):this.getZoomForExtent(OpenLayers.Layer.prototype.getExtent.apply(this,
1907 []))},getOLZoomFromMapObjectZoom:function(a){var b=null;null!=a&&(b=a-this.minZoomLevel,this.map.baseLayer!==this&&(b=this.map.baseLayer.getZoomForResolution(this.getResolutionForZoom(b))));return b},getMapObjectZoomFromOLZoom:function(a){var b=null;null!=a&&(b=a+this.minZoomLevel,this.map.baseLayer!==this&&(b=this.getZoomForResolution(this.map.baseLayer.getResolutionForZoom(b))));return b},CLASS_NAME:"OpenLayers.Layer.FixedZoomLevels"});OpenLayers.Layer.Google=OpenLayers.Class(OpenLayers.Layer.EventPane,OpenLayers.Layer.FixedZoomLevels,{MIN_ZOOM_LEVEL:0,MAX_ZOOM_LEVEL:21,RESOLUTIONS:[1.40625,0.703125,0.3515625,0.17578125,0.087890625,0.0439453125,0.02197265625,0.010986328125,0.0054931640625,0.00274658203125,0.001373291015625,6.866455078125E-4,3.4332275390625E-4,1.71661376953125E-4,8.58306884765625E-5,4.291534423828125E-5,2.145767211914062E-5,1.072883605957031E-5,5.36441802978515E-6,2.68220901489257E-6,1.341104507446289E-6,6.705522537231445E-7],
1908 type:null,wrapDateLine:!0,sphericalMercator:!1,version:null,initialize:function(a,b){b=b||{};b.version||(b.version="function"===typeof GMap2?"2":"3");var c=OpenLayers.Layer.Google["v"+b.version.replace(/\./g,"_")];if(c)OpenLayers.Util.applyDefaults(b,c);else throw"Unsupported Google Maps API version: "+b.version;OpenLayers.Util.applyDefaults(b,c.DEFAULTS);b.maxExtent&&(b.maxExtent=b.maxExtent.clone());OpenLayers.Layer.EventPane.prototype.initialize.apply(this,[a,b]);OpenLayers.Layer.FixedZoomLevels.prototype.initialize.apply(this,
1909 [a,b]);this.sphericalMercator&&(OpenLayers.Util.extend(this,OpenLayers.Layer.SphericalMercator),this.initMercatorParameters())},clone:function(){return new OpenLayers.Layer.Google(this.name,this.getOptions())},setVisibility:function(a){var b=null==this.opacity?1:this.opacity;OpenLayers.Layer.EventPane.prototype.setVisibility.apply(this,arguments);this.setOpacity(b)},display:function(a){this._dragging||this.setGMapVisibility(a);OpenLayers.Layer.EventPane.prototype.display.apply(this,arguments)},moveTo:function(a,
1910 b,c){this._dragging=c;OpenLayers.Layer.EventPane.prototype.moveTo.apply(this,arguments);delete this._dragging},setOpacity:function(a){a!==this.opacity&&(null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"opacity"}),this.opacity=a);if(this.getVisibility()){var b=this.getMapContainer();OpenLayers.Util.modifyDOMElement(b,null,null,null,null,null,null,a)}},destroy:function(){if(this.map){this.setGMapVisibility(!1);var a=OpenLayers.Layer.Google.cache[this.map.id];a&&1>=a.count&&
1911 this.removeGMapElements()}OpenLayers.Layer.EventPane.prototype.destroy.apply(this,arguments)},removeGMapElements:function(){var a=OpenLayers.Layer.Google.cache[this.map.id];if(a){var b=this.mapObject&&this.getMapContainer();b&&b.parentNode&&b.parentNode.removeChild(b);(b=a.termsOfUse)&&b.parentNode&&b.parentNode.removeChild(b);(a=a.poweredBy)&&a.parentNode&&a.parentNode.removeChild(a)}},removeMap:function(a){this.visibility&&this.mapObject&&this.setGMapVisibility(!1);var b=OpenLayers.Layer.Google.cache[a.id];
1912 b&&(1>=b.count?(this.removeGMapElements(),delete OpenLayers.Layer.Google.cache[a.id]):--b.count);delete this.termsOfUse;delete this.poweredBy;delete this.mapObject;delete this.dragObject;OpenLayers.Layer.EventPane.prototype.removeMap.apply(this,arguments)},getOLBoundsFromMapObjectBounds:function(a){var b=null;null!=a&&(b=a.getSouthWest(),a=a.getNorthEast(),this.sphericalMercator?(b=this.forwardMercator(b.lng(),b.lat()),a=this.forwardMercator(a.lng(),a.lat())):(b=new OpenLayers.LonLat(b.lng(),b.lat()),
1913 a=new OpenLayers.LonLat(a.lng(),a.lat())),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat));return b},getWarningHTML:function(){return OpenLayers.i18n("googleWarning")},getMapObjectCenter:function(){return this.mapObject.getCenter()},getMapObjectZoom:function(){return this.mapObject.getZoom()},getLongitudeFromMapObjectLonLat:function(a){return this.sphericalMercator?this.forwardMercator(a.lng(),a.lat()).lon:a.lng()},getLatitudeFromMapObjectLonLat:function(a){return this.sphericalMercator?this.forwardMercator(a.lng(),
1914 a.lat()).lat:a.lat()},getXFromMapObjectPixel:function(a){return a.x},getYFromMapObjectPixel:function(a){return a.y},CLASS_NAME:"OpenLayers.Layer.Google"});OpenLayers.Layer.Google.cache={};
1915 OpenLayers.Layer.Google.v2={termsOfUse:null,poweredBy:null,dragObject:null,loadMapObject:function(){this.type||(this.type=G_NORMAL_MAP);var a,b,c,d=OpenLayers.Layer.Google.cache[this.map.id];if(d)a=d.mapObject,b=d.termsOfUse,c=d.poweredBy,++d.count;else{var d=this.map.viewPortDiv,e=document.createElement("div");e.id=this.map.id+"_GMap2Container";e.style.position="absolute";e.style.width="100%";e.style.height="100%";d.appendChild(e);try{a=new GMap2(e),b=e.lastChild,d.appendChild(b),b.style.zIndex=
1916 "1100",b.style.right="",b.style.bottom="",b.className="olLayerGoogleCopyright",c=e.lastChild,d.appendChild(c),c.style.zIndex="1100",c.style.right="",c.style.bottom="",c.className="olLayerGooglePoweredBy gmnoprint"}catch(f){throw f;}OpenLayers.Layer.Google.cache[this.map.id]={mapObject:a,termsOfUse:b,poweredBy:c,count:1}}this.mapObject=a;this.termsOfUse=b;this.poweredBy=c;-1===OpenLayers.Util.indexOf(this.mapObject.getMapTypes(),this.type)&&this.mapObject.addMapType(this.type);"function"==typeof a.getDragObject?
1917 this.dragObject=a.getDragObject():this.dragPanMapObject=null;!1===this.isBaseLayer&&this.setGMapVisibility("none"!==this.div.style.display)},onMapResize:function(){if(this.visibility&&this.mapObject.isLoaded())this.mapObject.checkResize();else{if(!this._resized)var a=this,b=GEvent.addListener(this.mapObject,"load",function(){GEvent.removeListener(b);delete a._resized;a.mapObject.checkResize();a.moveTo(a.map.getCenter(),a.map.getZoom())});this._resized=!0}},setGMapVisibility:function(a){var b=OpenLayers.Layer.Google.cache[this.map.id];
1918 if(b){var c=this.mapObject.getContainer();!0===a?(this.mapObject.setMapType(this.type),c.style.display="",this.termsOfUse.style.left="",this.termsOfUse.style.display="",this.poweredBy.style.display="",b.displayed=this.id):(b.displayed===this.id&&delete b.displayed,b.displayed||(c.style.display="none",this.termsOfUse.style.display="none",this.termsOfUse.style.left="-9999px",this.poweredBy.style.display="none"))}},getMapContainer:function(){return this.mapObject.getContainer()},getMapObjectBoundsFromOLBounds:function(a){var b=
1919 null;null!=a&&(b=this.sphericalMercator?this.inverseMercator(a.bottom,a.left):new OpenLayers.LonLat(a.bottom,a.left),a=this.sphericalMercator?this.inverseMercator(a.top,a.right):new OpenLayers.LonLat(a.top,a.right),b=new GLatLngBounds(new GLatLng(b.lat,b.lon),new GLatLng(a.lat,a.lon)));return b},setMapObjectCenter:function(a,b){this.mapObject.setCenter(a,b)},dragPanMapObject:function(a,b){this.dragObject.moveBy(new GSize(-a,b))},getMapObjectLonLatFromMapObjectPixel:function(a){return this.mapObject.fromContainerPixelToLatLng(a)},
1920 getMapObjectPixelFromMapObjectLonLat:function(a){return this.mapObject.fromLatLngToContainerPixel(a)},getMapObjectZoomFromMapObjectBounds:function(a){return this.mapObject.getBoundsZoomLevel(a)},getMapObjectLonLatFromLonLat:function(a,b){var c;this.sphericalMercator?(c=this.inverseMercator(a,b),c=new GLatLng(c.lat,c.lon)):c=new GLatLng(b,a);return c},getMapObjectPixelFromXY:function(a,b){return new GPoint(a,b)}};OpenLayers.Format.XML=OpenLayers.Class(OpenLayers.Format,{namespaces:null,namespaceAlias:null,defaultPrefix:null,readers:{},writers:{},xmldom:null,initialize:function(a){window.ActiveXObject&&(this.xmldom=new ActiveXObject("Microsoft.XMLDOM"));OpenLayers.Format.prototype.initialize.apply(this,[a]);this.namespaces=OpenLayers.Util.extend({},this.namespaces);this.namespaceAlias={};for(var b in this.namespaces)this.namespaceAlias[this.namespaces[b]]=b},destroy:function(){this.xmldom=null;OpenLayers.Format.prototype.destroy.apply(this,
1921 arguments)},setNamespace:function(a,b){this.namespaces[a]=b;this.namespaceAlias[b]=a},read:function(a){var b=a.indexOf("<");0<b&&(a=a.substring(b));b=OpenLayers.Util.Try(OpenLayers.Function.bind(function(){var b;b=window.ActiveXObject&&!this.xmldom?new ActiveXObject("Microsoft.XMLDOM"):this.xmldom;b.loadXML(a);return b},this),function(){return(new DOMParser).parseFromString(a,"text/xml")},function(){var b=new XMLHttpRequest;b.open("GET","data:text/xml;charset=utf-8,"+encodeURIComponent(a),!1);b.overrideMimeType&&
1922 b.overrideMimeType("text/xml");b.send(null);return b.responseXML});this.keepData&&(this.data=b);return b},write:function(a){if(this.xmldom)a=a.xml;else{var b=new XMLSerializer;if(1==a.nodeType){var c=document.implementation.createDocument("","",null);c.importNode&&(a=c.importNode(a,!0));c.appendChild(a);a=b.serializeToString(c)}else a=b.serializeToString(a)}return a},createElementNS:function(a,b){return this.xmldom?"string"==typeof a?this.xmldom.createNode(1,b,a):this.xmldom.createNode(1,b,""):document.createElementNS(a,
1923 b)},createTextNode:function(a){"string"!==typeof a&&(a=""+a);return this.xmldom?this.xmldom.createTextNode(a):document.createTextNode(a)},getElementsByTagNameNS:function(a,b,c){var d=[];if(a.getElementsByTagNameNS)d=a.getElementsByTagNameNS(b,c);else for(var a=a.getElementsByTagName("*"),e,f,g=0,h=a.length;g<h;++g)if(e=a[g],f=e.prefix?e.prefix+":"+c:c,"*"==c||f==e.nodeName)("*"==b||b==e.namespaceURI)&&d.push(e);return d},getAttributeNodeNS:function(a,b,c){var d=null;if(a.getAttributeNodeNS)d=a.getAttributeNodeNS(b,
1924 c);else for(var a=a.attributes,e,f,g=0,h=a.length;g<h;++g)if(e=a[g],e.namespaceURI==b&&(f=e.prefix?e.prefix+":"+c:c,f==e.nodeName)){d=e;break}return d},getAttributeNS:function(a,b,c){var d="";if(a.getAttributeNS)d=a.getAttributeNS(b,c)||"";else if(a=this.getAttributeNodeNS(a,b,c))d=a.nodeValue;return d},getChildValue:function(a,b){var c=b||"";if(a)for(var d=a.firstChild;d;d=d.nextSibling)switch(d.nodeType){case 3:case 4:c+=d.nodeValue}return c},isSimpleContent:function(a){for(var b=!0,a=a.firstChild;a;a=
1925 a.nextSibling)if(1===a.nodeType){b=!1;break}return b},contentType:function(a){for(var b=!1,c=!1,d=OpenLayers.Format.XML.CONTENT_TYPE.EMPTY,a=a.firstChild;a;a=a.nextSibling){switch(a.nodeType){case 1:c=!0;break;case 8:break;default:b=!0}if(c&&b)break}if(c&&b)d=OpenLayers.Format.XML.CONTENT_TYPE.MIXED;else{if(c)return OpenLayers.Format.XML.CONTENT_TYPE.COMPLEX;if(b)return OpenLayers.Format.XML.CONTENT_TYPE.SIMPLE}return d},hasAttributeNS:function(a,b,c){var d=!1;return d=a.hasAttributeNS?a.hasAttributeNS(b,
1926 c):!!this.getAttributeNodeNS(a,b,c)},setAttributeNS:function(a,b,c,d){if(a.setAttributeNS)a.setAttributeNS(b,c,d);else if(this.xmldom)b?(b=a.ownerDocument.createNode(2,c,b),b.nodeValue=d,a.setAttributeNode(b)):a.setAttribute(c,d);else throw"setAttributeNS not implemented";},createElementNSPlus:function(a,b){var b=b||{},c=b.uri||this.namespaces[b.prefix];c||(c=a.indexOf(":"),c=this.namespaces[a.substring(0,c)]);c||(c=this.namespaces[this.defaultPrefix]);c=this.createElementNS(c,a);b.attributes&&this.setAttributes(c,
1927 b.attributes);var d=b.value;null!=d&&c.appendChild(this.createTextNode(d));return c},setAttributes:function(a,b){var c,d,e;for(e in b)null!=b[e]&&b[e].toString&&(c=b[e].toString(),d=this.namespaces[e.substring(0,e.indexOf(":"))]||null,this.setAttributeNS(a,d,e,c))},readNode:function(a,b){b||(b={});var c=this.readers[a.namespaceURI?this.namespaceAlias[a.namespaceURI]:this.defaultPrefix];if(c){var d=a.localName||a.nodeName.split(":").pop();(c=c[d]||c["*"])&&c.apply(this,[a,b])}return b},readChildNodes:function(a,
1928 b){b||(b={});for(var c=a.childNodes,d,e=0,f=c.length;e<f;++e)d=c[e],1==d.nodeType&&this.readNode(d,b);return b},writeNode:function(a,b,c){var d,e=a.indexOf(":");0<e?(d=a.substring(0,e),a=a.substring(e+1)):d=c?this.namespaceAlias[c.namespaceURI]:this.defaultPrefix;b=this.writers[d][a].apply(this,[b]);c&&c.appendChild(b);return b},getChildEl:function(a,b,c){return a&&this.getThisOrNextEl(a.firstChild,b,c)},getNextEl:function(a,b,c){return a&&this.getThisOrNextEl(a.nextSibling,b,c)},getThisOrNextEl:function(a,
1929 b,c){a:for(;a;a=a.nextSibling)switch(a.nodeType){case 1:if((!b||b===(a.localName||a.nodeName.split(":").pop()))&&(!c||c===a.namespaceURI))break a;a=null;break a;case 3:if(/^\s*$/.test(a.nodeValue))break;case 4:case 6:case 12:case 10:case 11:a=null;break a}return a||null},lookupNamespaceURI:function(a,b){var c=null;if(a)if(a.lookupNamespaceURI)c=a.lookupNamespaceURI(b);else a:switch(a.nodeType){case 1:if(null!==a.namespaceURI&&a.prefix===b){c=a.namespaceURI;break a}if(c=a.attributes.length)for(var d,
1930 e=0;e<c;++e)if(d=a.attributes[e],"xmlns"===d.prefix&&d.name==="xmlns:"+b){c=d.value||null;break a}else if("xmlns"===d.name&&null===b){c=d.value||null;break a}c=this.lookupNamespaceURI(a.parentNode,b);break a;case 2:c=this.lookupNamespaceURI(a.ownerElement,b);break a;case 9:c=this.lookupNamespaceURI(a.documentElement,b);break a;case 6:case 12:case 10:case 11:break a;default:c=this.lookupNamespaceURI(a.parentNode,b)}return c},getXMLDoc:function(){!OpenLayers.Format.XML.document&&!this.xmldom&&(document.implementation&&
1931 document.implementation.createDocument?OpenLayers.Format.XML.document=document.implementation.createDocument("","",null):!this.xmldom&&window.ActiveXObject&&(this.xmldom=new ActiveXObject("Microsoft.XMLDOM")));return OpenLayers.Format.XML.document||this.xmldom},CLASS_NAME:"OpenLayers.Format.XML"});OpenLayers.Format.XML.CONTENT_TYPE={EMPTY:0,SIMPLE:1,COMPLEX:2,MIXED:3};OpenLayers.Format.XML.lookupNamespaceURI=OpenLayers.Function.bind(OpenLayers.Format.XML.prototype.lookupNamespaceURI,OpenLayers.Format.XML.prototype);
1932 OpenLayers.Format.XML.document=null;OpenLayers.Format.WFST=function(a){var a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.WFST.DEFAULTS),b=OpenLayers.Format.WFST["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFST version: "+a.version;return new b(a)};OpenLayers.Format.WFST.DEFAULTS={version:"1.0.0"};OpenLayers.Format.WFST.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs",gml:"http://www.opengis.net/gml",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows"},defaultPrefix:"wfs",version:null,schemaLocations:null,srsName:null,extractAttributes:!0,xy:!0,stateName:null,initialize:function(a){this.stateName={};this.stateName[OpenLayers.State.INSERT]="wfs:Insert";this.stateName[OpenLayers.State.UPDATE]=
1933 "wfs:Update";this.stateName[OpenLayers.State.DELETE]="wfs:Delete";OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},getSrsName:function(a,b){var c=b&&b.srsName;c||(c=a&&a.layer?a.layer.projection.getCode():this.srsName);return c},read:function(a,b){b=b||{};OpenLayers.Util.applyDefaults(b,{output:"features"});"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var c={};a&&this.readNode(a,c,!0);c.features&&"features"===b.output&&
1934 (c=c.features);return c},readers:{wfs:{FeatureCollection:function(a,b){b.features=[];this.readChildNodes(a,b)}}},write:function(a,b){var c=this.writeNode("wfs:Transaction",{features:a,options:b}),d=this.schemaLocationAttr();d&&this.setAttributeNS(c,this.namespaces.xsi,"xsi:schemaLocation",d);return OpenLayers.Format.XML.prototype.write.apply(this,[c])},writers:{wfs:{GetFeature:function(a){var b=this.createElementNSPlus("wfs:GetFeature",{attributes:{service:"WFS",version:this.version,handle:a&&a.handle,
1935 outputFormat:a&&a.outputFormat,maxFeatures:a&&a.maxFeatures,"xsi:schemaLocation":this.schemaLocationAttr(a)}});if("string"==typeof this.featureType)this.writeNode("Query",a,b);else for(var c=0,d=this.featureType.length;c<d;c++)a.featureType=this.featureType[c],this.writeNode("Query",a,b);return b},Transaction:function(a){var a=a||{},b=a.options||{},c=this.createElementNSPlus("wfs:Transaction",{attributes:{service:"WFS",version:this.version,handle:b.handle}}),d,e=a.features;if(e){!0===b.multi&&OpenLayers.Util.extend(this.geometryTypes,
1936 {"OpenLayers.Geometry.Point":"MultiPoint","OpenLayers.Geometry.LineString":!0===this.multiCurve?"MultiCurve":"MultiLineString","OpenLayers.Geometry.Polygon":!0===this.multiSurface?"MultiSurface":"MultiPolygon"});var f,g,a=0;for(d=e.length;a<d;++a)g=e[a],(f=this.stateName[g.state])&&this.writeNode(f,{feature:g,options:b},c);!0===b.multi&&this.setGeometryTypes()}if(b.nativeElements){a=0;for(d=b.nativeElements.length;a<d;++a)this.writeNode("wfs:Native",b.nativeElements[a],c)}return c},Native:function(a){return this.createElementNSPlus("wfs:Native",
1937 {attributes:{vendorId:a.vendorId,safeToIgnore:a.safeToIgnore},value:a.value})},Insert:function(a){var b=a.feature,a=a.options,a=this.createElementNSPlus("wfs:Insert",{attributes:{handle:a&&a.handle}});this.srsName=this.getSrsName(b);this.writeNode("feature:_typeName",b,a);return a},Update:function(a){var b=a.feature,a=a.options,a=this.createElementNSPlus("wfs:Update",{attributes:{handle:a&&a.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+this.featureType}});this.featureNS&&a.setAttribute("xmlns:"+
1938 this.featurePrefix,this.featureNS);var c=b.modified;if(null!==this.geometryName&&(!c||void 0!==c.geometry))this.srsName=this.getSrsName(b),this.writeNode("Property",{name:this.geometryName,value:b.geometry},a);for(var d in b.attributes)void 0!==b.attributes[d]&&(!c||!c.attributes||c.attributes&&void 0!==c.attributes[d])&&this.writeNode("Property",{name:d,value:b.attributes[d]},a);this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[b.fid]}),a);return a},Property:function(a){var b=this.createElementNSPlus("wfs:Property");
1939 this.writeNode("Name",a.name,b);null!==a.value&&this.writeNode("Value",a.value,b);return b},Name:function(a){return this.createElementNSPlus("wfs:Name",{value:a})},Value:function(a){var b;a instanceof OpenLayers.Geometry?(b=this.createElementNSPlus("wfs:Value"),a=this.writeNode("feature:_geometry",a).firstChild,b.appendChild(a)):b=this.createElementNSPlus("wfs:Value",{value:a});return b},Delete:function(a){var b=a.feature,a=a.options,a=this.createElementNSPlus("wfs:Delete",{attributes:{handle:a&&
1940 a.handle,typeName:(this.featureNS?this.featurePrefix+":":"")+this.featureType}});this.featureNS&&a.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);this.writeNode("ogc:Filter",new OpenLayers.Filter.FeatureId({fids:[b.fid]}),a);return a}}},schemaLocationAttr:function(a){var a=OpenLayers.Util.extend({featurePrefix:this.featurePrefix,schema:this.schema},a),b=OpenLayers.Util.extend({},this.schemaLocations);a.schema&&(b[a.featurePrefix]=a.schema);var a=[],c,d;for(d in b)(c=this.namespaces[d])&&
1941 a.push(c+" "+b[d]);return a.join(" ")||void 0},setFilterProperty:function(a){if(a.filters)for(var b=0,c=a.filters.length;b<c;++b)OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this,a.filters[b]);else a instanceof OpenLayers.Filter.Spatial&&!a.property&&(a.property=this.geometryName)},CLASS_NAME:"OpenLayers.Format.WFST.v1"});OpenLayers.Format.OGCExceptionReport=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},defaultPrefix:"ogc",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b={exceptionReport:null};a.documentElement&&(this.readChildNodes(a,b),null===b.exceptionReport&&(b=(new OpenLayers.Format.OWSCommon).read(a)));return b},readers:{ogc:{ServiceExceptionReport:function(a,
1942 b){b.exceptionReport={exceptions:[]};this.readChildNodes(a,b.exceptionReport)},ServiceException:function(a,b){var c={code:a.getAttribute("code"),locator:a.getAttribute("locator"),text:this.getChildValue(a)};b.exceptions.push(c)}}},CLASS_NAME:"OpenLayers.Format.OGCExceptionReport"});OpenLayers.Format.XML.VersionedOGC=OpenLayers.Class(OpenLayers.Format.XML,{defaultVersion:null,version:null,profile:null,errorProperty:null,name:null,stringifyOutput:!1,parser:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);a=this.CLASS_NAME;this.name=a.substring(a.lastIndexOf(".")+1)},getVersion:function(a,b){var c;a?(c=this.version,c||(c=a.getAttribute("version"),c||(c=this.defaultVersion))):c=b&&b.version||this.version||this.defaultVersion;return c},getParser:function(a){var a=
1943 a||this.defaultVersion,b=this.profile?"_"+this.profile:"";if(!this.parser||this.parser.VERSION!=a){var c=OpenLayers.Format[this.name]["v"+a.replace(/\./g,"_")+b];if(!c)throw"Can't find a "+this.name+" parser for version "+a+b;this.parser=new c(this.options)}return this.parser},write:function(a,b){this.parser=this.getParser(this.getVersion(null,b));var c=this.parser.write(a,b);return!1===this.stringifyOutput?c:OpenLayers.Format.XML.prototype.write.apply(this,[c])},read:function(a,b){"string"==typeof a&&
1944 (a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var c=this.getVersion(a.documentElement);this.parser=this.getParser(c);var d=this.parser.read(a,b);if(null!==this.errorProperty&&void 0===d[this.errorProperty]){var e=new OpenLayers.Format.OGCExceptionReport;d.error=e.read(a)}d.version=c;return d},CLASS_NAME:"OpenLayers.Format.XML.VersionedOGC"});OpenLayers.Feature=OpenLayers.Class({layer:null,id:null,lonlat:null,data:null,marker:null,popupClass:null,popup:null,initialize:function(a,b,c){this.layer=a;this.lonlat=b;this.data=null!=c?c:{};this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){null!=this.layer&&null!=this.layer.map&&null!=this.popup&&this.layer.map.removePopup(this.popup);null!=this.layer&&null!=this.marker&&this.layer.removeMarker(this.marker);this.data=this.lonlat=this.id=this.layer=null;null!=this.marker&&
1945 (this.destroyMarker(this.marker),this.marker=null);null!=this.popup&&(this.destroyPopup(this.popup),this.popup=null)},onScreen:function(){var a=!1;null!=this.layer&&null!=this.layer.map&&(a=this.layer.map.getExtent().containsLonLat(this.lonlat));return a},createMarker:function(){null!=this.lonlat&&(this.marker=new OpenLayers.Marker(this.lonlat,this.data.icon));return this.marker},destroyMarker:function(){this.marker.destroy()},createPopup:function(a){null!=this.lonlat&&(this.popup||(this.popup=new (this.popupClass?
1946 this.popupClass:OpenLayers.Popup.Anchored)(this.id+"_popup",this.lonlat,this.data.popupSize,this.data.popupContentHTML,this.marker?this.marker.icon:null,a)),null!=this.data.overflow&&(this.popup.contentDiv.style.overflow=this.data.overflow),this.popup.feature=this);return this.popup},destroyPopup:function(){this.popup&&(this.popup.feature=null,this.popup.destroy(),this.popup=null)},CLASS_NAME:"OpenLayers.Feature"});OpenLayers.State={UNKNOWN:"Unknown",INSERT:"Insert",UPDATE:"Update",DELETE:"Delete"};
1947 OpenLayers.Feature.Vector=OpenLayers.Class(OpenLayers.Feature,{fid:null,geometry:null,attributes:null,bounds:null,state:null,style:null,url:null,renderIntent:"default",modified:null,initialize:function(a,b,c){OpenLayers.Feature.prototype.initialize.apply(this,[null,null,b]);this.lonlat=null;this.geometry=a?a:null;this.state=null;this.attributes={};b&&(this.attributes=OpenLayers.Util.extend(this.attributes,b));this.style=c?c:null},destroy:function(){this.layer&&(this.layer.removeFeatures(this),this.layer=
1948 null);this.modified=this.geometry=null;OpenLayers.Feature.prototype.destroy.apply(this,arguments)},clone:function(){return new OpenLayers.Feature.Vector(this.geometry?this.geometry.clone():null,this.attributes,this.style)},onScreen:function(a){var b=!1;this.layer&&this.layer.map&&(b=this.layer.map.getExtent(),a?(a=this.geometry.getBounds(),b=b.intersectsBounds(a)):b=b.toGeometry().intersects(this.geometry));return b},getVisibility:function(){return!(this.style&&"none"==this.style.display||!this.layer||
1949 this.layer&&this.layer.styleMap&&"none"==this.layer.styleMap.createSymbolizer(this,this.renderIntent).display||this.layer&&!this.layer.getVisibility())},createMarker:function(){return null},destroyMarker:function(){},createPopup:function(){return null},atPoint:function(a,b,c){var d=!1;this.geometry&&(d=this.geometry.atPoint(a,b,c));return d},destroyPopup:function(){},move:function(a){if(this.layer&&this.geometry.move){var a="OpenLayers.LonLat"==a.CLASS_NAME?this.layer.getViewPortPxFromLonLat(a):a,
1950 b=this.layer.getViewPortPxFromLonLat(this.geometry.getBounds().getCenterLonLat()),c=this.layer.map.getResolution();this.geometry.move(c*(a.x-b.x),c*(b.y-a.y));this.layer.drawFeature(this);return b}},toState:function(a){if(a==OpenLayers.State.UPDATE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.DELETE:this.state=a}else if(a==OpenLayers.State.INSERT)switch(this.state){case OpenLayers.State.UNKNOWN:break;default:this.state=a}else if(a==OpenLayers.State.DELETE)switch(this.state){case OpenLayers.State.UNKNOWN:case OpenLayers.State.UPDATE:this.state=
1951 a}else a==OpenLayers.State.UNKNOWN&&(this.state=a)},CLASS_NAME:"OpenLayers.Feature.Vector"});
1952 OpenLayers.Feature.Vector.style={"default":{fillColor:"#ee9900",fillOpacity:0.4,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#ee9900",strokeOpacity:1,strokeWidth:1,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},select:{fillColor:"blue",fillOpacity:0.4,
1953 hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"blue",strokeOpacity:1,strokeWidth:2,strokeLinecap:"round",strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"pointer",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},temporary:{fillColor:"#66cccc",fillOpacity:0.2,hoverFillColor:"white",hoverFillOpacity:0.8,strokeColor:"#66cccc",strokeOpacity:1,
1954 strokeLinecap:"round",strokeWidth:2,strokeDashstyle:"solid",hoverStrokeColor:"red",hoverStrokeOpacity:1,hoverStrokeWidth:0.2,pointRadius:6,hoverPointRadius:1,hoverPointUnit:"%",pointerEvents:"visiblePainted",cursor:"inherit",fontColor:"#000000",labelAlign:"cm",labelOutlineColor:"white",labelOutlineWidth:3},"delete":{display:"none"}};OpenLayers.Style=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,context:null,defaultStyle:null,defaultsPerSymbolizer:!1,propertyStyles:null,initialize:function(a,b){OpenLayers.Util.extend(this,b);this.rules=[];b&&b.rules&&this.addRules(b.rules);this.setDefaultStyle(a||OpenLayers.Feature.Vector.style["default"]);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;a<b;a++)this.rules[a].destroy(),
1955 this.rules[a]=null;this.defaultStyle=this.rules=null},createSymbolizer:function(a){for(var b=this.defaultsPerSymbolizer?{}:this.createLiterals(OpenLayers.Util.extend({},this.defaultStyle),a),c=this.rules,d,e=[],f=!1,g=0,h=c.length;g<h;g++)d=c[g],d.evaluate(a)&&(d instanceof OpenLayers.Rule&&d.elseFilter?e.push(d):(f=!0,this.applySymbolizer(d,b,a)));if(!1==f&&0<e.length){f=!0;g=0;for(h=e.length;g<h;g++)this.applySymbolizer(e[g],b,a)}0<c.length&&!1==f&&(b.display="none");null!=b.label&&"string"!==typeof b.label&&
1956 (b.label=""+b.label);return b},applySymbolizer:function(a,b,c){var d=c.geometry?this.getSymbolizerPrefix(c.geometry):OpenLayers.Style.SYMBOLIZER_PREFIXES[0],a=a.symbolizer[d]||a.symbolizer;!0===this.defaultsPerSymbolizer&&(d=this.defaultStyle,OpenLayers.Util.applyDefaults(a,{pointRadius:d.pointRadius}),(!0===a.stroke||!0===a.graphic)&&OpenLayers.Util.applyDefaults(a,{strokeWidth:d.strokeWidth,strokeColor:d.strokeColor,strokeOpacity:d.strokeOpacity,strokeDashstyle:d.strokeDashstyle,strokeLinecap:d.strokeLinecap}),
1957 (!0===a.fill||!0===a.graphic)&&OpenLayers.Util.applyDefaults(a,{fillColor:d.fillColor,fillOpacity:d.fillOpacity}),!0===a.graphic&&OpenLayers.Util.applyDefaults(a,{pointRadius:this.defaultStyle.pointRadius,externalGraphic:this.defaultStyle.externalGraphic,graphicName:this.defaultStyle.graphicName,graphicOpacity:this.defaultStyle.graphicOpacity,graphicWidth:this.defaultStyle.graphicWidth,graphicHeight:this.defaultStyle.graphicHeight,graphicXOffset:this.defaultStyle.graphicXOffset,graphicYOffset:this.defaultStyle.graphicYOffset}));
1958 return this.createLiterals(OpenLayers.Util.extend(b,a),c)},createLiterals:function(a,b){var c=OpenLayers.Util.extend({},b.attributes||b.data);OpenLayers.Util.extend(c,this.context);for(var d in this.propertyStyles)a[d]=OpenLayers.Style.createLiteral(a[d],c,b,d);return a},findPropertyStyles:function(){var a={};this.addPropertyStyles(a,this.defaultStyle);for(var b=this.rules,c,d,e=0,f=b.length;e<f;e++){c=b[e].symbolizer;for(var g in c)if(d=c[g],"object"==typeof d)this.addPropertyStyles(a,d);else{this.addPropertyStyles(a,
1959 c);break}}return a},addPropertyStyles:function(a,b){var c,d;for(d in b)c=b[d],"string"==typeof c&&c.match(/\$\{\w+\}/)&&(a[d]=!0);return a},addRules:function(a){Array.prototype.push.apply(this.rules,a);this.propertyStyles=this.findPropertyStyles()},setDefaultStyle:function(a){this.defaultStyle=a;this.propertyStyles=this.findPropertyStyles()},getSymbolizerPrefix:function(a){for(var b=OpenLayers.Style.SYMBOLIZER_PREFIXES,c=0,d=b.length;c<d;c++)if(-1!=a.CLASS_NAME.indexOf(b[c]))return b[c]},clone:function(){var a=
1960 OpenLayers.Util.extend({},this);if(this.rules){a.rules=[];for(var b=0,c=this.rules.length;b<c;++b)a.rules.push(this.rules[b].clone())}a.context=this.context&&OpenLayers.Util.extend({},this.context);b=OpenLayers.Util.extend({},this.defaultStyle);return new OpenLayers.Style(b,a)},CLASS_NAME:"OpenLayers.Style"});OpenLayers.Style.createLiteral=function(a,b,c,d){"string"==typeof a&&-1!=a.indexOf("${")&&(a=OpenLayers.String.format(a,b,[c,d]),a=isNaN(a)||!a?a:parseFloat(a));return a};
1961 OpenLayers.Style.SYMBOLIZER_PREFIXES=["Point","Line","Polygon","Text","Raster"];OpenLayers.Filter=OpenLayers.Class({initialize:function(a){OpenLayers.Util.extend(this,a)},destroy:function(){},evaluate:function(){return!0},clone:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.CQL?OpenLayers.Format.CQL.prototype.write(this):Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Filter"});OpenLayers.Filter.FeatureId=OpenLayers.Class(OpenLayers.Filter,{fids:null,type:"FID",initialize:function(a){this.fids=[];OpenLayers.Filter.prototype.initialize.apply(this,[a])},evaluate:function(a){for(var b=0,c=this.fids.length;b<c;b++)if((a.fid||a.id)==this.fids[b])return!0;return!1},clone:function(){var a=new OpenLayers.Filter.FeatureId;OpenLayers.Util.extend(a,this);a.fids=this.fids.slice();return a},CLASS_NAME:"OpenLayers.Filter.FeatureId"});OpenLayers.Filter.Logical=OpenLayers.Class(OpenLayers.Filter,{filters:null,type:null,initialize:function(a){this.filters=[];OpenLayers.Filter.prototype.initialize.apply(this,[a])},destroy:function(){this.filters=null;OpenLayers.Filter.prototype.destroy.apply(this)},evaluate:function(a){var b,c;switch(this.type){case OpenLayers.Filter.Logical.AND:b=0;for(c=this.filters.length;b<c;b++)if(!1==this.filters[b].evaluate(a))return!1;return!0;case OpenLayers.Filter.Logical.OR:b=0;for(c=this.filters.length;b<
1962 c;b++)if(!0==this.filters[b].evaluate(a))return!0;return!1;case OpenLayers.Filter.Logical.NOT:return!this.filters[0].evaluate(a)}},clone:function(){for(var a=[],b=0,c=this.filters.length;b<c;++b)a.push(this.filters[b].clone());return new OpenLayers.Filter.Logical({type:this.type,filters:a})},CLASS_NAME:"OpenLayers.Filter.Logical"});OpenLayers.Filter.Logical.AND="&&";OpenLayers.Filter.Logical.OR="||";OpenLayers.Filter.Logical.NOT="!";OpenLayers.Filter.Comparison=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,matchCase:!0,lowerBoundary:null,upperBoundary:null,initialize:function(a){OpenLayers.Filter.prototype.initialize.apply(this,[a]);this.type===OpenLayers.Filter.Comparison.LIKE&&void 0===a.matchCase&&(this.matchCase=null)},evaluate:function(a){a instanceof OpenLayers.Feature.Vector&&(a=a.attributes);var b=!1,a=a[this.property];switch(this.type){case OpenLayers.Filter.Comparison.EQUAL_TO:b=this.value;
1963 b=!this.matchCase&&"string"==typeof a&&"string"==typeof b?a.toUpperCase()==b.toUpperCase():a==b;break;case OpenLayers.Filter.Comparison.NOT_EQUAL_TO:b=this.value;b=!this.matchCase&&"string"==typeof a&&"string"==typeof b?a.toUpperCase()!=b.toUpperCase():a!=b;break;case OpenLayers.Filter.Comparison.LESS_THAN:b=a<this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN:b=a>this.value;break;case OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO:b=a<=this.value;break;case OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO:b=
1964 a>=this.value;break;case OpenLayers.Filter.Comparison.BETWEEN:b=a>=this.lowerBoundary&&a<=this.upperBoundary;break;case OpenLayers.Filter.Comparison.LIKE:b=RegExp(this.value,"gi").test(a)}return b},value2regex:function(a,b,c){if("."==a)throw Error("'.' is an unsupported wildCard character for OpenLayers.Filter.Comparison");a=a?a:"*";b=b?b:".";this.value=this.value.replace(RegExp("\\"+(c?c:"!")+"(.|$)","g"),"\\$1");this.value=this.value.replace(RegExp("\\"+b,"g"),".");this.value=this.value.replace(RegExp("\\"+
1965 a,"g"),".*");this.value=this.value.replace(RegExp("\\\\.\\*","g"),"\\"+a);return this.value=this.value.replace(RegExp("\\\\\\.","g"),"\\"+b)},regex2value:function(){var a=this.value,a=a.replace(/!/g,"!!"),a=a.replace(/(\\)?\\\./g,function(a,c){return c?a:"!."}),a=a.replace(/(\\)?\\\*/g,function(a,c){return c?a:"!*"}),a=a.replace(/\\\\/g,"\\");return a=a.replace(/\.\*/g,"*")},clone:function(){return OpenLayers.Util.extend(new OpenLayers.Filter.Comparison,this)},CLASS_NAME:"OpenLayers.Filter.Comparison"});
1966 OpenLayers.Filter.Comparison.EQUAL_TO="==";OpenLayers.Filter.Comparison.NOT_EQUAL_TO="!=";OpenLayers.Filter.Comparison.LESS_THAN="<";OpenLayers.Filter.Comparison.GREATER_THAN=">";OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO="<=";OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO=">=";OpenLayers.Filter.Comparison.BETWEEN="..";OpenLayers.Filter.Comparison.LIKE="~";OpenLayers.Format.Filter=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.Filter"});OpenLayers.Filter.Function=OpenLayers.Class(OpenLayers.Filter,{name:null,params:null,CLASS_NAME:"OpenLayers.Filter.Function"});OpenLayers.Format.Filter.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"ogc",schemaLocation:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){var b={};this.readers.ogc.Filter.apply(this,[a,b]);return b.filter},readers:{ogc:{_expression:function(a){for(var b="",c=a.firstChild;c;c=
1967 c.nextSibling)switch(c.nodeType){case 1:a=this.readNode(c);a.property?b+="${"+a.property+"}":void 0!==a.value&&(b+=a.value);break;case 3:case 4:b+=c.nodeValue}return b},Filter:function(a,b){var c={fids:[],filters:[]};this.readChildNodes(a,c);0<c.fids.length?b.filter=new OpenLayers.Filter.FeatureId({fids:c.fids}):0<c.filters.length&&(b.filter=c.filters[0])},FeatureId:function(a,b){var c=a.getAttribute("fid");c&&b.fids.push(c)},And:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND});
1968 this.readChildNodes(a,c);b.filters.push(c)},Or:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.OR});this.readChildNodes(a,c);b.filters.push(c)},Not:function(a,b){var c=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.NOT});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThan:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThan:function(a,
1969 b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLessThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsGreaterThanOrEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},
1970 PropertyIsBetween:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.BETWEEN});this.readChildNodes(a,c);b.filters.push(c)},Literal:function(a,b){b.value=OpenLayers.String.numericIf(this.getChildValue(a))},PropertyName:function(a,b){b.property=this.getChildValue(a)},LowerBoundary:function(a,b){b.lowerBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,a))},UpperBoundary:function(a,b){b.upperBoundary=OpenLayers.String.numericIf(this.readers.ogc._expression.call(this,
1971 a))},Intersects:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.INTERSECTS)},Within:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.WITHIN)},Contains:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.CONTAINS)},DWithin:function(a,b){this.readSpatial(a,b,OpenLayers.Filter.Spatial.DWITHIN)},Distance:function(a,b){b.distance=parseInt(this.getChildValue(a));b.distanceUnits=a.getAttribute("units")},Function:function(){}}},readSpatial:function(a,b,c){c=new OpenLayers.Filter.Spatial({type:c});
1972 this.readChildNodes(a,c);c.value=c.components[0];delete c.components;b.filters.push(c)},writeOgcExpression:function(a,b){if(a instanceof OpenLayers.Filter.Function){var c=this.writeNode("Function",a,b);b.appendChild(c)}else this.writeNode("Literal",a,b);return b},write:function(a){return this.writers.ogc.Filter.apply(this,[a])},writeFeatureIdNodes:function(a,b){for(var c=0,d=a.fids.length;c<d;++c)this.writeNode("FeatureId",a.fids[c],b)},writers:{ogc:{Filter:function(a){var b=this.createElementNSPlus("ogc:Filter");
1973 "FID"===a.type?OpenLayers.Format.Filter.v1.prototype.writeFeatureIdNodes.call(this,a,b):this.writeNode(this.getFilterType(a),a,b);return b},FeatureId:function(a){return this.createElementNSPlus("ogc:FeatureId",{attributes:{fid:a}})},And:function(a){for(var b=this.createElementNSPlus("ogc:And"),c,d=0,e=a.filters.length;d<e;++d)c=a.filters[d],"FID"===c.type?OpenLayers.Format.Filter.v1.prototype.writeFeatureIdNodes.call(this,c,b):this.writeNode(this.getFilterType(c),c,b);return b},Or:function(a){for(var b=
1974 this.createElementNSPlus("ogc:Or"),c,d=0,e=a.filters.length;d<e;++d)c=a.filters[d],"FID"===c.type?OpenLayers.Format.Filter.v1.prototype.writeFeatureIdNodes.call(this,c,b):this.writeNode(this.getFilterType(c),c,b);return b},Not:function(a){var b=this.createElementNSPlus("ogc:Not"),a=a.filters[0];"FID"===a.type?OpenLayers.Format.Filter.v1.prototype.writeFeatureIdNodes.call(this,a,b):this.writeNode(this.getFilterType(a),a,b);return b},PropertyIsLessThan:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLessThan");
1975 this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsGreaterThan:function(a){var b=this.createElementNSPlus("ogc:PropertyIsGreaterThan");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLessThanOrEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLessThanOrEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsGreaterThanOrEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsGreaterThanOrEqualTo");
1976 this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsBetween:function(a){var b=this.createElementNSPlus("ogc:PropertyIsBetween");this.writeNode("PropertyName",a,b);this.writeNode("LowerBoundary",a,b);this.writeNode("UpperBoundary",a,b);return b},PropertyName:function(a){return this.createElementNSPlus("ogc:PropertyName",{value:a.property})},Literal:function(a){return this.createElementNSPlus("ogc:Literal",{value:a})},LowerBoundary:function(a){var b=this.createElementNSPlus("ogc:LowerBoundary");
1977 this.writeOgcExpression(a.lowerBoundary,b);return b},UpperBoundary:function(a){var b=this.createElementNSPlus("ogc:UpperBoundary");this.writeNode("Literal",a.upperBoundary,b);return b},INTERSECTS:function(a){return this.writeSpatial(a,"Intersects")},WITHIN:function(a){return this.writeSpatial(a,"Within")},CONTAINS:function(a){return this.writeSpatial(a,"Contains")},DWITHIN:function(a){var b=this.writeSpatial(a,"DWithin");this.writeNode("Distance",a,b);return b},Distance:function(a){return this.createElementNSPlus("ogc:Distance",
1978 {attributes:{units:a.distanceUnits},value:a.distance})},Function:function(a){for(var b=this.createElementNSPlus("ogc:Function",{attributes:{name:a.name}}),a=a.params,c=0,d=a.length;c<d;c++)this.writeOgcExpression(a[c],b);return b}}},getFilterType:function(a){var b=this.filterMap[a.type];if(!b)throw"Filter writing not supported for rule type: "+a.type;return b},filterMap:{"&&":"And","||":"Or","!":"Not","==":"PropertyIsEqualTo","!=":"PropertyIsNotEqualTo","<":"PropertyIsLessThan",">":"PropertyIsGreaterThan",
1979 "<=":"PropertyIsLessThanOrEqualTo",">=":"PropertyIsGreaterThanOrEqualTo","..":"PropertyIsBetween","~":"PropertyIsLike",BBOX:"BBOX",DWITHIN:"DWITHIN",WITHIN:"WITHIN",CONTAINS:"CONTAINS",INTERSECTS:"INTERSECTS",FID:"FeatureId"},CLASS_NAME:"OpenLayers.Format.Filter.v1"});OpenLayers.Geometry=OpenLayers.Class({id:null,parent:null,bounds:null,initialize:function(){this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){this.bounds=this.id=null},clone:function(){return new OpenLayers.Geometry},setBounds:function(a){a&&(this.bounds=a.clone())},clearBounds:function(){this.bounds=null;this.parent&&this.parent.clearBounds()},extendBounds:function(a){this.getBounds()?this.bounds.extend(a):this.setBounds(a)},getBounds:function(){null==this.bounds&&this.calculateBounds();
1980 return this.bounds},calculateBounds:function(){},distanceTo:function(){},getVertices:function(){},atPoint:function(a,b,c){var d=!1;null!=this.getBounds()&&null!=a&&(b=null!=b?b:0,c=null!=c?c:0,d=(new OpenLayers.Bounds(this.bounds.left-b,this.bounds.bottom-c,this.bounds.right+b,this.bounds.top+c)).containsLonLat(a));return d},getLength:function(){return 0},getArea:function(){return 0},getCentroid:function(){return null},toString:function(){return OpenLayers.Format&&OpenLayers.Format.WKT?OpenLayers.Format.WKT.prototype.write(new OpenLayers.Feature.Vector(this)):
1981 Object.prototype.toString.call(this)},CLASS_NAME:"OpenLayers.Geometry"});OpenLayers.Geometry.fromWKT=function(a){var b;if(OpenLayers.Format&&OpenLayers.Format.WKT){var c=OpenLayers.Geometry.fromWKT.format;c||(c=new OpenLayers.Format.WKT,OpenLayers.Geometry.fromWKT.format=c);a=c.read(a);if(a instanceof OpenLayers.Feature.Vector)b=a.geometry;else if(OpenLayers.Util.isArray(a)){b=a.length;for(var c=Array(b),d=0;d<b;++d)c[d]=a[d].geometry;b=new OpenLayers.Geometry.Collection(c)}}return b};
1982 OpenLayers.Geometry.segmentsIntersect=function(a,b,c){var d=c&&c.point,c=c&&c.tolerance,e=!1,f=a.x1-b.x1,g=a.y1-b.y1,h=a.x2-a.x1,i=a.y2-a.y1,j=b.y2-b.y1,k=b.x2-b.x1,l=j*h-k*i,j=k*g-j*f,g=h*g-i*f;0==l?0==j&&0==g&&(e=!0):(f=j/l,l=g/l,0<=f&&(1>=f&&0<=l&&1>=l)&&(d?(h=a.x1+f*h,l=a.y1+f*i,e=new OpenLayers.Geometry.Point(h,l)):e=!0));if(c)if(e){if(d){a=[a,b];b=0;a:for(;2>b;++b){f=a[b];for(i=1;3>i;++i)if(h=f["x"+i],l=f["y"+i],d=Math.sqrt(Math.pow(h-e.x,2)+Math.pow(l-e.y,2)),d<c){e.x=h;e.y=l;break a}}}}else{a=
1983 [a,b];b=0;a:for(;2>b;++b){h=a[b];l=a[(b+1)%2];for(i=1;3>i;++i)if(f={x:h["x"+i],y:h["y"+i]},g=OpenLayers.Geometry.distanceToSegment(f,l),g.distance<c){e=d?new OpenLayers.Geometry.Point(f.x,f.y):!0;break a}}}return e};OpenLayers.Geometry.distanceToSegment=function(a,b){var c=a.x,d=a.y,e=b.x1,f=b.y1,g=b.x2,h=b.y2,i=g-e,j=h-f,k=(i*(c-e)+j*(d-f))/(Math.pow(i,2)+Math.pow(j,2));0>=k||(1<=k?(e=g,f=h):(e+=k*i,f+=k*j));return{distance:Math.sqrt(Math.pow(e-c,2)+Math.pow(f-d,2)),x:e,y:f}};OpenLayers.Geometry.Point=OpenLayers.Class(OpenLayers.Geometry,{x:null,y:null,initialize:function(a,b){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.x=parseFloat(a);this.y=parseFloat(b)},clone:function(a){null==a&&(a=new OpenLayers.Geometry.Point(this.x,this.y));OpenLayers.Util.applyDefaults(a,this);return a},calculateBounds:function(){this.bounds=new OpenLayers.Bounds(this.x,this.y,this.x,this.y)},distanceTo:function(a,b){var c=!(b&&!1===b.edge)&&b&&b.details,d,e,f,g,h;a instanceof
1984 OpenLayers.Geometry.Point?(e=this.x,f=this.y,g=a.x,h=a.y,d=Math.sqrt(Math.pow(e-g,2)+Math.pow(f-h,2)),d=!c?d:{x0:e,y0:f,x1:g,y1:h,distance:d}):(d=a.distanceTo(this,b),c&&(d={x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0,distance:d.distance}));return d},equals:function(a){var b=!1;null!=a&&(b=this.x==a.x&&this.y==a.y||isNaN(this.x)&&isNaN(this.y)&&isNaN(a.x)&&isNaN(a.y));return b},toShortString:function(){return this.x+", "+this.y},move:function(a,b){this.x+=a;this.y+=b;this.clearBounds()},rotate:function(a,b){var a=
1985 a*(Math.PI/180),c=this.distanceTo(b),d=a+Math.atan2(this.y-b.y,this.x-b.x);this.x=b.x+c*Math.cos(d);this.y=b.y+c*Math.sin(d);this.clearBounds()},getCentroid:function(){return new OpenLayers.Geometry.Point(this.x,this.y)},resize:function(a,b,c){this.x=b.x+a*(void 0==c?1:c)*(this.x-b.x);this.y=b.y+a*(this.y-b.y);this.clearBounds();return this},intersects:function(a){var b=!1;return b="OpenLayers.Geometry.Point"==a.CLASS_NAME?this.equals(a):a.intersects(this)},transform:function(a,b){a&&b&&(OpenLayers.Projection.transform(this,
1986 a,b),this.bounds=null);return this},getVertices:function(){return[this]},CLASS_NAME:"OpenLayers.Geometry.Point"});OpenLayers.Geometry.Collection=OpenLayers.Class(OpenLayers.Geometry,{components:null,componentTypes:null,initialize:function(a){OpenLayers.Geometry.prototype.initialize.apply(this,arguments);this.components=[];null!=a&&this.addComponents(a)},destroy:function(){this.components.length=0;this.components=null;OpenLayers.Geometry.prototype.destroy.apply(this,arguments)},clone:function(){for(var a=eval("new "+this.CLASS_NAME+"()"),b=0,c=this.components.length;b<c;b++)a.addComponent(this.components[b].clone());
1987 OpenLayers.Util.applyDefaults(a,this);return a},getComponentsString:function(){for(var a=[],b=0,c=this.components.length;b<c;b++)a.push(this.components[b].toShortString());return a.join(",")},calculateBounds:function(){this.bounds=null;var a=new OpenLayers.Bounds,b=this.components;if(b)for(var c=0,d=b.length;c<d;c++)a.extend(b[c].getBounds());null!=a.left&&(null!=a.bottom&&null!=a.right&&null!=a.top)&&this.setBounds(a)},addComponents:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b<
1988 c;b++)this.addComponent(a[b])},addComponent:function(a,b){var c=!1;if(a&&(null==this.componentTypes||-1<OpenLayers.Util.indexOf(this.componentTypes,a.CLASS_NAME))){if(null!=b&&b<this.components.length){var c=this.components.slice(0,b),d=this.components.slice(b,this.components.length);c.push(a);this.components=c.concat(d)}else this.components.push(a);a.parent=this;this.clearBounds();c=!0}return c},removeComponents:function(a){var b=!1;OpenLayers.Util.isArray(a)||(a=[a]);for(var c=a.length-1;0<=c;--c)b=
1989 this.removeComponent(a[c])||b;return b},removeComponent:function(a){OpenLayers.Util.removeItem(this.components,a);this.clearBounds();return!0},getLength:function(){for(var a=0,b=0,c=this.components.length;b<c;b++)a+=this.components[b].getLength();return a},getArea:function(){for(var a=0,b=0,c=this.components.length;b<c;b++)a+=this.components[b].getArea();return a},getGeodesicArea:function(a){for(var b=0,c=0,d=this.components.length;c<d;c++)b+=this.components[c].getGeodesicArea(a);return b},getCentroid:function(a){if(!a)return this.components.length&&
1990 this.components[0].getCentroid();a=this.components.length;if(!a)return!1;for(var b=[],c=[],d=0,e=Number.MAX_VALUE,f,g=0;g<a;++g){f=this.components[g];var h=f.getArea();f=f.getCentroid(!0);!isNaN(h)&&(!isNaN(f.x)&&!isNaN(f.y))&&(b.push(h),d+=h,e=h<e&&0<h?h:e,c.push(f))}a=b.length;if(0===d){for(g=0;g<a;++g)b[g]=1;d=b.length}else{for(g=0;g<a;++g)b[g]/=e;d/=e}for(var i=e=0,g=0;g<a;++g)f=c[g],h=b[g],e+=f.x*h,i+=f.y*h;return new OpenLayers.Geometry.Point(e/d,i/d)},getGeodesicLength:function(a){for(var b=
1991 0,c=0,d=this.components.length;c<d;c++)b+=this.components[c].getGeodesicLength(a);return b},move:function(a,b){for(var c=0,d=this.components.length;c<d;c++)this.components[c].move(a,b)},rotate:function(a,b){for(var c=0,d=this.components.length;c<d;++c)this.components[c].rotate(a,b)},resize:function(a,b,c){for(var d=0;d<this.components.length;++d)this.components[d].resize(a,b,c);return this},distanceTo:function(a,b){for(var c=!(b&&!1===b.edge)&&b&&b.details,d,e,f,g=Number.POSITIVE_INFINITY,h=0,i=this.components.length;h<
1992 i&&!(d=this.components[h].distanceTo(a,b),f=c?d.distance:d,f<g&&(g=f,e=d,0==g));++h);return e},equals:function(a){var b=!0;if(!a||!a.CLASS_NAME||this.CLASS_NAME!=a.CLASS_NAME)b=!1;else if(!OpenLayers.Util.isArray(a.components)||a.components.length!=this.components.length)b=!1;else for(var c=0,d=this.components.length;c<d;++c)if(!this.components[c].equals(a.components[c])){b=!1;break}return b},transform:function(a,b){if(a&&b){for(var c=0,d=this.components.length;c<d;c++)this.components[c].transform(a,
1993 b);this.bounds=null}return this},intersects:function(a){for(var b=!1,c=0,d=this.components.length;c<d&&!(b=a.intersects(this.components[c]));++c);return b},getVertices:function(a){for(var b=[],c=0,d=this.components.length;c<d;++c)Array.prototype.push.apply(b,this.components[c].getVertices(a));return b},CLASS_NAME:"OpenLayers.Geometry.Collection"});OpenLayers.Geometry.MultiPoint=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Point"],addPoint:function(a,b){this.addComponent(a,b)},removePoint:function(a){this.removeComponent(a)},CLASS_NAME:"OpenLayers.Geometry.MultiPoint"});OpenLayers.Geometry.Curve=OpenLayers.Class(OpenLayers.Geometry.MultiPoint,{componentTypes:["OpenLayers.Geometry.Point"],getLength:function(){var a=0;if(this.components&&1<this.components.length)for(var b=1,c=this.components.length;b<c;b++)a+=this.components[b-1].distanceTo(this.components[b]);return a},getGeodesicLength:function(a){var b=this;if(a){var c=new OpenLayers.Projection("EPSG:4326");c.equals(a)||(b=this.clone().transform(a,c))}a=0;if(b.components&&1<b.components.length)for(var d,e=1,f=b.components.length;e<
1994 f;e++)c=b.components[e-1],d=b.components[e],a+=OpenLayers.Util.distVincenty({lon:c.x,lat:c.y},{lon:d.x,lat:d.y});return 1E3*a},CLASS_NAME:"OpenLayers.Geometry.Curve"});OpenLayers.Geometry.LineString=OpenLayers.Class(OpenLayers.Geometry.Curve,{removeComponent:function(a){var b=this.components&&2<this.components.length;b&&OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,arguments);return b},intersects:function(a){var b=!1,c=a.CLASS_NAME;if("OpenLayers.Geometry.LineString"==c||"OpenLayers.Geometry.LinearRing"==c||"OpenLayers.Geometry.Point"==c){var d=this.getSortedSegments(),a="OpenLayers.Geometry.Point"==c?[{x1:a.x,y1:a.y,x2:a.x,y2:a.y}]:a.getSortedSegments(),
1995 e,f,g,h,i,j,k,l=0,m=d.length;a:for(;l<m;++l){c=d[l];e=c.x1;f=c.x2;g=c.y1;h=c.y2;var n=0,o=a.length;for(;n<o;++n){i=a[n];if(i.x1>f)break;if(!(i.x2<e)&&(j=i.y1,k=i.y2,!(Math.min(j,k)>Math.max(g,h))&&!(Math.max(j,k)<Math.min(g,h))&&OpenLayers.Geometry.segmentsIntersect(c,i))){b=!0;break a}}}}else b=a.intersects(this);return b},getSortedSegments:function(){for(var a=this.components.length-1,b=Array(a),c,d,e=0;e<a;++e)c=this.components[e],d=this.components[e+1],b[e]=c.x<d.x?{x1:c.x,y1:c.y,x2:d.x,y2:d.y}:
1996 {x1:d.x,y1:d.y,x2:c.x,y2:c.y};return b.sort(function(a,b){return a.x1-b.x1})},splitWithSegment:function(a,b){for(var c=!(b&&!1===b.edge),d=b&&b.tolerance,e=[],f=this.getVertices(),g=[],h=[],i=!1,j,k,l,m={point:!0,tolerance:d},n=null,o=0,p=f.length-2;o<=p;++o)if(d=f[o],g.push(d.clone()),j=f[o+1],k={x1:d.x,y1:d.y,x2:j.x,y2:j.y},k=OpenLayers.Geometry.segmentsIntersect(a,k,m),k instanceof OpenLayers.Geometry.Point&&((l=k.x===a.x1&&k.y===a.y1||k.x===a.x2&&k.y===a.y2||k.equals(d)||k.equals(j)?!0:!1)||c))k.equals(h[h.length-
1997 1])||h.push(k.clone()),!(0===o&&k.equals(d))&&!k.equals(j)&&(i=!0,k.equals(d)||g.push(k),e.push(new OpenLayers.Geometry.LineString(g)),g=[k.clone()]);i&&(g.push(j.clone()),e.push(new OpenLayers.Geometry.LineString(g)));if(0<h.length)var q=a.x1<a.x2?1:-1,r=a.y1<a.y2?1:-1,n={lines:e,points:h.sort(function(a,b){return q*a.x-q*b.x||r*a.y-r*b.y})};return n},split:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h;if(a instanceof OpenLayers.Geometry.LineString){var i=this.getVertices(),j,k,l,m,n,o=[];g=[];
1998 for(var p=0,q=i.length-2;p<=q;++p){j=i[p];k=i[p+1];l={x1:j.x,y1:j.y,x2:k.x,y2:k.y};h=h||[a];d&&o.push(j.clone());for(var r=0;r<h.length;++r)if(m=h[r].splitWithSegment(l,b))if(n=m.lines,0<n.length&&(n.unshift(r,1),Array.prototype.splice.apply(h,n),r+=n.length-2),d)for(var s=0,t=m.points.length;s<t;++s)n=m.points[s],n.equals(j)||(o.push(n),g.push(new OpenLayers.Geometry.LineString(o)),o=n.equals(k)?[]:[n.clone()])}d&&(0<g.length&&0<o.length)&&(o.push(k.clone()),g.push(new OpenLayers.Geometry.LineString(o)))}else c=
1999 a.splitWith(this,b);h&&1<h.length?f=!0:h=[];g&&1<g.length?e=!0:g=[];if(f||e)c=d?[g,h]:h;return c},splitWith:function(a,b){return a.split(this,b)},getVertices:function(a){return!0===a?[this.components[0],this.components[this.components.length-1]]:!1===a?this.components.slice(1,this.components.length-1):this.components.slice()},distanceTo:function(a,b){var c=!(b&&!1===b.edge)&&b&&b.details,d,e={},f=Number.POSITIVE_INFINITY;if(a instanceof OpenLayers.Geometry.Point){for(var g=this.getSortedSegments(),
2000 h=a.x,i=a.y,j,k=0,l=g.length;k<l;++k)if(j=g[k],d=OpenLayers.Geometry.distanceToSegment(a,j),d.distance<f){if(f=d.distance,e=d,0===f)break}else if(j.x2>h&&(i>j.y1&&i<j.y2||i<j.y1&&i>j.y2))break;e=c?{distance:e.distance,x0:e.x,y0:e.y,x1:h,y1:i}:e.distance}else if(a instanceof OpenLayers.Geometry.LineString){var g=this.getSortedSegments(),h=a.getSortedSegments(),m,n,o=h.length,p={point:!0},k=0,l=g.length;a:for(;k<l;++k){i=g[k];j=i.x1;n=i.y1;for(var q=0;q<o;++q)if(d=h[q],m=OpenLayers.Geometry.segmentsIntersect(i,
2001 d,p)){f=0;e={distance:0,x0:m.x,y0:m.y,x1:m.x,y1:m.y};break a}else d=OpenLayers.Geometry.distanceToSegment({x:j,y:n},d),d.distance<f&&(f=d.distance,e={distance:f,x0:j,y0:n,x1:d.x,y1:d.y})}c||(e=e.distance);0!==f&&i&&(d=a.distanceTo(new OpenLayers.Geometry.Point(i.x2,i.y2),b),k=c?d.distance:d,k<f&&(e=c?{distance:f,x0:d.x1,y0:d.y1,x1:d.x0,y1:d.y0}:k))}else e=a.distanceTo(this,b),c&&(e={distance:e.distance,x0:e.x1,y0:e.y1,x1:e.x0,y1:e.y0});return e},simplify:function(a){if(this&&null!==this){var b=this.getVertices();
2002 if(3>b.length)return this;var c=function(a,b,d,i){for(var j=0,k=0,l=b,m;l<d;l++){m=a[b];var n=a[d],o=a[l],o=Math.abs(0.5*(m.x*n.y+n.x*o.y+o.x*m.y-n.x*m.y-o.x*n.y-m.x*o.y));m=Math.sqrt(Math.pow(m.x-n.x,2)+Math.pow(m.y-n.y,2));m=2*(o/m);m>j&&(j=m,k=l)}j>i&&k!=b&&(e.push(k),c(a,b,k,i),c(a,k,d,i))},d=b.length-1,e=[];e.push(0);for(e.push(d);b[0].equals(b[d]);)d--,e.push(d);c(b,0,d,a);a=[];e.sort(function(a,b){return a-b});for(d=0;d<e.length;d++)a.push(b[e[d]]);return new OpenLayers.Geometry.LineString(a)}return this},
2003 CLASS_NAME:"OpenLayers.Geometry.LineString"});OpenLayers.Geometry.MultiLineString=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LineString"],split:function(a,b){for(var c=null,d=b&&b.mutual,e,f,g,h,i=[],j=[a],k=0,l=this.components.length;k<l;++k){f=this.components[k];g=!1;for(var m=0;m<j.length;++m)if(e=f.split(j[m],b)){if(d){g=e[0];for(var n=0,o=g.length;n<o;++n)0===n&&i.length?i[i.length-1].addComponent(g[n]):i.push(new OpenLayers.Geometry.MultiLineString([g[n]]));g=!0;e=e[1]}if(e.length){e.unshift(m,
2004 1);Array.prototype.splice.apply(j,e);break}}g||(i.length?i[i.length-1].addComponent(f.clone()):i=[new OpenLayers.Geometry.MultiLineString(f.clone())])}i&&1<i.length?g=!0:i=[];j&&1<j.length?h=!0:j=[];if(g||h)c=d?[i,j]:j;return c},splitWith:function(a,b){var c=null,d=b&&b.mutual,e,f,g,h,i,j;if(a instanceof OpenLayers.Geometry.LineString){j=[];i=[a];for(var k=0,l=this.components.length;k<l;++k){g=!1;f=this.components[k];for(var m=0;m<i.length;++m)if(e=i[m].split(f,b)){d&&(g=e[0],g.length&&(g.unshift(m,
2005 1),Array.prototype.splice.apply(i,g),m+=g.length-2),e=e[1],0===e.length&&(e=[f.clone()]));g=0;for(var n=e.length;g<n;++g)0===g&&j.length?j[j.length-1].addComponent(e[g]):j.push(new OpenLayers.Geometry.MultiLineString([e[g]]));g=!0}g||(j.length?j[j.length-1].addComponent(f.clone()):j=[new OpenLayers.Geometry.MultiLineString([f.clone()])])}}else c=a.split(this);i&&1<i.length?h=!0:i=[];j&&1<j.length?g=!0:j=[];if(h||g)c=d?[i,j]:j;return c},CLASS_NAME:"OpenLayers.Geometry.MultiLineString"});OpenLayers.Geometry.LinearRing=OpenLayers.Class(OpenLayers.Geometry.LineString,{componentTypes:["OpenLayers.Geometry.Point"],addComponent:function(a,b){var c=!1,d=this.components.pop();if(null!=b||!a.equals(d))c=OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,arguments);OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]);return c},removeComponent:function(a){var b=this.components&&3<this.components.length;b&&(this.components.pop(),OpenLayers.Geometry.Collection.prototype.removeComponent.apply(this,
2006 arguments),OpenLayers.Geometry.Collection.prototype.addComponent.apply(this,[this.components[0]]));return b},move:function(a,b){for(var c=0,d=this.components.length;c<d-1;c++)this.components[c].move(a,b)},rotate:function(a,b){for(var c=0,d=this.components.length;c<d-1;++c)this.components[c].rotate(a,b)},resize:function(a,b,c){for(var d=0,e=this.components.length;d<e-1;++d)this.components[d].resize(a,b,c);return this},transform:function(a,b){if(a&&b){for(var c=0,d=this.components.length;c<d-1;c++)this.components[c].transform(a,
2007 b);this.bounds=null}return this},getCentroid:function(){if(this.components&&2<this.components.length){for(var a=0,b=0,c=0;c<this.components.length-1;c++)var d=this.components[c],e=this.components[c+1],a=a+(d.x+e.x)*(d.x*e.y-e.x*d.y),b=b+(d.y+e.y)*(d.x*e.y-e.x*d.y);c=-1*this.getArea();return new OpenLayers.Geometry.Point(a/(6*c),b/(6*c))}return null},getArea:function(){var a=0;if(this.components&&2<this.components.length){for(var b=a=0,c=this.components.length;b<c-1;b++)var d=this.components[b],e=
2008 this.components[b+1],a=a+(d.x+e.x)*(e.y-d.y);a=-a/2}return a},getGeodesicArea:function(a){var b=this;if(a){var c=new OpenLayers.Projection("EPSG:4326");c.equals(a)||(b=this.clone().transform(a,c))}a=0;c=b.components&&b.components.length;if(2<c){for(var d,e,f=0;f<c-1;f++)d=b.components[f],e=b.components[f+1],a+=OpenLayers.Util.rad(e.x-d.x)*(2+Math.sin(OpenLayers.Util.rad(d.y))+Math.sin(OpenLayers.Util.rad(e.y)));a=40680631590769*a/2}return a},containsPoint:function(a){for(var b=OpenLayers.Number.limitSigDigs,
2009 c=b(a.x,14),a=b(a.y,14),d=this.components.length-1,e,f,g,h,i,j=0,k=0;k<d;++k)if(e=this.components[k],g=b(e.x,14),e=b(e.y,14),f=this.components[k+1],h=b(f.x,14),f=b(f.y,14),e==f){if(a==e&&(g<=h&&c>=g&&c<=h||g>=h&&c<=g&&c>=h)){j=-1;break}}else{i=b((a-f)*((h-g)/(f-e))+h,14);if(i==c&&(e<f&&a>=e&&a<=f||e>f&&a<=e&&a>=f)){j=-1;break}i<=c||g!=h&&(i<Math.min(g,h)||i>Math.max(g,h))||(e<f&&a>=e&&a<f||e>f&&a<e&&a>=f)&&++j}return-1==j?1:!!(j&1)},intersects:function(a){var b=!1;if("OpenLayers.Geometry.Point"==
2010 a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME)b=a.intersects(this);else if("OpenLayers.Geometry.LinearRing"==a.CLASS_NAME)b=OpenLayers.Geometry.LineString.prototype.intersects.apply(this,[a]);else for(var c=0,d=a.components.length;c<d&&!(b=a.components[c].intersects(this));++c);return b},getVertices:function(a){return!0===a?[]:this.components.slice(0,this.components.length-1)},CLASS_NAME:"OpenLayers.Geometry.LinearRing"});OpenLayers.Geometry.Polygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.LinearRing"],getArea:function(){var a=0;if(this.components&&0<this.components.length)for(var a=a+Math.abs(this.components[0].getArea()),b=1,c=this.components.length;b<c;b++)a-=Math.abs(this.components[b].getArea());return a},getGeodesicArea:function(a){var b=0;if(this.components&&0<this.components.length)for(var b=b+Math.abs(this.components[0].getGeodesicArea(a)),c=1,d=this.components.length;c<
2011 d;c++)b-=Math.abs(this.components[c].getGeodesicArea(a));return b},containsPoint:function(a){var b=this.components.length,c=!1;if(0<b&&(c=this.components[0].containsPoint(a),1!==c&&c&&1<b))for(var d,e=1;e<b;++e)if(d=this.components[e].containsPoint(a)){c=1===d?1:!1;break}return c},intersects:function(a){var b=!1,c,d;if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.containsPoint(a);else if("OpenLayers.Geometry.LineString"==a.CLASS_NAME||"OpenLayers.Geometry.LinearRing"==a.CLASS_NAME){c=0;for(d=
2012 this.components.length;c<d&&!(b=a.intersects(this.components[c]));++c);if(!b){c=0;for(d=a.components.length;c<d&&!(b=this.containsPoint(a.components[c]));++c);}}else{c=0;for(d=a.components.length;c<d&&!(b=this.intersects(a.components[c]));++c);}if(!b&&"OpenLayers.Geometry.Polygon"==a.CLASS_NAME){var e=this.components[0];c=0;for(d=e.components.length;c<d&&!(b=a.containsPoint(e.components[c]));++c);}return b},distanceTo:function(a,b){return b&&!1===b.edge&&this.intersects(a)?0:OpenLayers.Geometry.Collection.prototype.distanceTo.apply(this,
2013 [a,b])},CLASS_NAME:"OpenLayers.Geometry.Polygon"});OpenLayers.Geometry.Polygon.createRegularPolygon=function(a,b,c,d){var e=Math.PI*(1/c-0.5);d&&(e+=d/180*Math.PI);for(var f,g=[],h=0;h<c;++h)f=e+2*h*Math.PI/c,d=a.x+b*Math.cos(f),f=a.y+b*Math.sin(f),g.push(new OpenLayers.Geometry.Point(d,f));a=new OpenLayers.Geometry.LinearRing(g);return new OpenLayers.Geometry.Polygon([a])};OpenLayers.Geometry.MultiPolygon=OpenLayers.Class(OpenLayers.Geometry.Collection,{componentTypes:["OpenLayers.Geometry.Polygon"],CLASS_NAME:"OpenLayers.Geometry.MultiPolygon"});OpenLayers.Format.GML=OpenLayers.Class(OpenLayers.Format.XML,{featureNS:"http://mapserver.gis.umn.edu/mapserver",featurePrefix:"feature",featureName:"featureMember",layerName:"features",geometryName:"geometry",collectionName:"FeatureCollection",gmlns:"http://www.opengis.net/gml",extractAttributes:!0,xy:!0,initialize:function(a){this.regExes={trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g};OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==
2014 typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var a=this.getElementsByTagNameNS(a.documentElement,this.gmlns,this.featureName),b=[],c=0;c<a.length;c++){var d=this.parseFeature(a[c]);d&&b.push(d)}return b},parseFeature:function(a){for(var b="MultiPolygon Polygon MultiLineString LineString MultiPoint Point Envelope".split(" "),c,d,e,f=0;f<b.length;++f)if(c=b[f],d=this.getElementsByTagNameNS(a,this.gmlns,c),0<d.length){if(e=this.parseGeometry[c.toLowerCase()])e=e.apply(this,
2015 [d[0]]),this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection);else throw new TypeError("Unsupported geometry type: "+c);break}var g;c=this.getElementsByTagNameNS(a,this.gmlns,"Box");for(f=0;f<c.length;++f)b=c[f],d=this.parseGeometry.box.apply(this,[b]),b=b.parentNode,"boundedBy"===(b.localName||b.nodeName.split(":").pop())?g=d:e=d.toGeometry();var h;this.extractAttributes&&(h=this.parseAttributes(a));h=new OpenLayers.Feature.Vector(e,h);h.bounds=
2016 g;h.gml={featureType:a.firstChild.nodeName.split(":")[1],featureNS:a.firstChild.namespaceURI,featureNSPrefix:a.firstChild.prefix};for(var a=a.firstChild,i;a&&!(1==a.nodeType&&(i=a.getAttribute("fid")||a.getAttribute("id")));)a=a.nextSibling;h.fid=i;return h},parseGeometry:{point:function(a){var b,c;c=[];b=this.getElementsByTagNameNS(a,this.gmlns,"pos");0<b.length&&(c=b[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));0==c.length&&(b=this.getElementsByTagNameNS(a,
2017 this.gmlns,"coordinates"),0<b.length&&(c=b[0].firstChild.nodeValue,c=c.replace(this.regExes.removeSpace,""),c=c.split(",")));0==c.length&&(b=this.getElementsByTagNameNS(a,this.gmlns,"coord"),0<b.length&&(a=this.getElementsByTagNameNS(b[0],this.gmlns,"X"),b=this.getElementsByTagNameNS(b[0],this.gmlns,"Y"),0<a.length&&0<b.length&&(c=[a[0].firstChild.nodeValue,b[0].firstChild.nodeValue])));2==c.length&&(c[2]=null);return this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],
2018 c[0],c[2])},multipoint:function(a){var a=this.getElementsByTagNameNS(a,this.gmlns,"Point"),b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.point.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiPoint(b)},linestring:function(a,b){var c,d;d=[];var e=[];c=this.getElementsByTagNameNS(a,this.gmlns,"posList");if(0<c.length){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.split(this.regExes.splitSpace);var f=parseInt(c[0].getAttribute("dimension")),
2019 g,h,i;for(c=0;c<d.length/f;++c)g=c*f,h=d[g],i=d[g+1],g=2==f?null:d[g+2],this.xy?e.push(new OpenLayers.Geometry.Point(h,i,g)):e.push(new OpenLayers.Geometry.Point(i,h,g))}if(0==d.length&&(c=this.getElementsByTagNameNS(a,this.gmlns,"coordinates"),0<c.length)){d=this.getChildValue(c[0]);d=d.replace(this.regExes.trimSpace,"");d=d.replace(this.regExes.trimComma,",");f=d.split(this.regExes.splitSpace);for(c=0;c<f.length;++c)d=f[c].split(","),2==d.length&&(d[2]=null),this.xy?e.push(new OpenLayers.Geometry.Point(d[0],
2020 d[1],d[2])):e.push(new OpenLayers.Geometry.Point(d[1],d[0],d[2]))}d=null;0!=e.length&&(d=b?new OpenLayers.Geometry.LinearRing(e):new OpenLayers.Geometry.LineString(e));return d},multilinestring:function(a){var a=this.getElementsByTagNameNS(a,this.gmlns,"LineString"),b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.linestring.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiLineString(b)},polygon:function(a){var a=this.getElementsByTagNameNS(a,this.gmlns,"LinearRing"),
2021 b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.linestring.apply(this,[a[d],!0]))&&b.push(c);return new OpenLayers.Geometry.Polygon(b)},multipolygon:function(a){var a=this.getElementsByTagNameNS(a,this.gmlns,"Polygon"),b=[];if(0<a.length)for(var c,d=0;d<a.length;++d)(c=this.parseGeometry.polygon.apply(this,[a[d]]))&&b.push(c);return new OpenLayers.Geometry.MultiPolygon(b)},envelope:function(a){var b=[],c,d,e=this.getElementsByTagNameNS(a,this.gmlns,"lowerCorner");if(0<e.length){c=
2022 [];0<e.length&&(c=e[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));2==c.length&&(c[2]=null);var f=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}a=this.getElementsByTagNameNS(a,this.gmlns,"upperCorner");if(0<a.length){c=[];0<a.length&&(c=a[0].firstChild.nodeValue,c=c.replace(this.regExes.trimSpace,""),c=c.split(this.regExes.splitSpace));2==c.length&&(c[2]=null);var g=this.xy?new OpenLayers.Geometry.Point(c[0],
2023 c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2])}f&&g&&(b.push(new OpenLayers.Geometry.Point(f.x,f.y)),b.push(new OpenLayers.Geometry.Point(g.x,f.y)),b.push(new OpenLayers.Geometry.Point(g.x,g.y)),b.push(new OpenLayers.Geometry.Point(f.x,g.y)),b.push(new OpenLayers.Geometry.Point(f.x,f.y)),b=new OpenLayers.Geometry.LinearRing(b),d=new OpenLayers.Geometry.Polygon([b]));return d},box:function(a){var b=this.getElementsByTagNameNS(a,this.gmlns,"coordinates"),c=a=null;0<b.length&&(b=b[0].firstChild.nodeValue,
2024 b=b.split(" "),2==b.length&&(a=b[0].split(","),c=b[1].split(",")));if(null!==a&&null!==c)return new OpenLayers.Bounds(parseFloat(a[0]),parseFloat(a[1]),parseFloat(c[0]),parseFloat(c[1]))}},parseAttributes:function(a){for(var b={},a=a.firstChild,c,d,e;a;){if(1==a.nodeType){a=a.childNodes;for(c=0;c<a.length;++c)if(d=a[c],1==d.nodeType)if(e=d.childNodes,1==e.length){if(e=e[0],3==e.nodeType||4==e.nodeType)d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,e=e.nodeValue.replace(this.regExes.trimSpace,""),
2025 b[d]=e}else b[d.nodeName.split(":").pop()]=null;break}a=a.nextSibling}return b},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=this.createElementNS("http://www.opengis.net/wfs","wfs:"+this.collectionName),c=0;c<a.length;c++)b.appendChild(this.createFeatureXML(a[c]));return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.featureNS,this.featurePrefix+":"+this.geometryName);c.appendChild(b);
2026 var b=this.createElementNS(this.gmlns,"gml:"+this.featureName),d=this.createElementNS(this.featureNS,this.featurePrefix+":"+this.layerName);d.setAttribute("fid",a.fid||a.id);d.appendChild(c);for(var e in a.attributes){var c=this.createTextNode(a.attributes[e]),f=this.createElementNS(this.featureNS,this.featurePrefix+":"+e.substring(e.lastIndexOf(":")+1));f.appendChild(c);d.appendChild(f)}b.appendChild(d);return b},buildGeometryNode:function(a){this.externalProjection&&this.internalProjection&&(a=
2027 a.clone(),a.transform(this.internalProjection,this.externalProjection));var b=a.CLASS_NAME;return this.buildGeometry[b.substring(b.lastIndexOf(".")+1).toLowerCase()].apply(this,[a])},buildGeometry:{point:function(a){var b=this.createElementNS(this.gmlns,"gml:Point");b.appendChild(this.buildCoordinatesNode(a));return b},multipoint:function(a){for(var b=this.createElementNS(this.gmlns,"gml:MultiPoint"),a=a.components,c,d,e=0;e<a.length;e++)c=this.createElementNS(this.gmlns,"gml:pointMember"),d=this.buildGeometry.point.apply(this,
2028 [a[e]]),c.appendChild(d),b.appendChild(c);return b},linestring:function(a){var b=this.createElementNS(this.gmlns,"gml:LineString");b.appendChild(this.buildCoordinatesNode(a));return b},multilinestring:function(a){for(var b=this.createElementNS(this.gmlns,"gml:MultiLineString"),a=a.components,c,d,e=0;e<a.length;++e)c=this.createElementNS(this.gmlns,"gml:lineStringMember"),d=this.buildGeometry.linestring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},linearring:function(a){var b=this.createElementNS(this.gmlns,
2029 "gml:LinearRing");b.appendChild(this.buildCoordinatesNode(a));return b},polygon:function(a){for(var b=this.createElementNS(this.gmlns,"gml:Polygon"),a=a.components,c,d,e=0;e<a.length;++e)c=0==e?"outerBoundaryIs":"innerBoundaryIs",c=this.createElementNS(this.gmlns,"gml:"+c),d=this.buildGeometry.linearring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},multipolygon:function(a){for(var b=this.createElementNS(this.gmlns,"gml:MultiPolygon"),a=a.components,c,d,e=0;e<a.length;++e)c=this.createElementNS(this.gmlns,
2030 "gml:polygonMember"),d=this.buildGeometry.polygon.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},bounds:function(a){var b=this.createElementNS(this.gmlns,"gml:Box");b.appendChild(this.buildCoordinatesNode(a));return b}},buildCoordinatesNode:function(a){var b=this.createElementNS(this.gmlns,"gml:coordinates");b.setAttribute("decimal",".");b.setAttribute("cs",",");b.setAttribute("ts"," ");var c=[];if(a instanceof OpenLayers.Bounds)c.push(a.left+","+a.bottom),c.push(a.right+","+a.top);
2031 else for(var a=a.components?a.components:[a],d=0;d<a.length;d++)c.push(a[d].x+","+a[d].y);c=this.createTextNode(c.join(" "));b.appendChild(c);return b},CLASS_NAME:"OpenLayers.Format.GML"});OpenLayers.Format.GML||(OpenLayers.Format.GML={});
2032 OpenLayers.Format.GML.Base=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",wfs:"http://www.opengis.net/wfs"},defaultPrefix:"gml",schemaLocation:null,featureType:null,featureNS:null,geometryName:"geometry",extractAttributes:!0,srsName:null,xy:!0,geometryTypes:null,singleFeatureType:null,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,featureMember:/^(.*:)?featureMembers?$/},
2033 initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.setGeometryTypes();a&&a.featureNS&&this.setNamespace("feature",a.featureNS);this.singleFeatureType=!a||typeof a.featureType==="string"},read:function(a){typeof a=="string"&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));if(a&&a.nodeType==9)a=a.documentElement;var b=[];this.readNode(a,{features:b},true);if(b.length==0){var c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMember");if(c.length)for(var a=
2034 0,d=c.length;a<d;++a)this.readNode(c[a],{features:b},true);else{c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMembers");c.length&&this.readNode(c[0],{features:b},true)}}return b},readNode:function(a,b,c){if(c===true&&this.autoConfig===true){this.featureType=null;delete this.namespaceAlias[this.featureNS];delete this.namespaces.feature;this.featureNS=null}if(!this.featureNS&&!(a.prefix in this.namespaces)&&a.parentNode.namespaceURI==this.namespaces.gml&&this.regExes.featureMember.test(a.parentNode.nodeName)){this.featureType=
2035 a.nodeName.split(":").pop();this.setNamespace("feature",a.namespaceURI);this.featureNS=a.namespaceURI;this.autoConfig=true}return OpenLayers.Format.XML.prototype.readNode.apply(this,[a,b])},readers:{gml:{featureMember:function(a,b){this.readChildNodes(a,b)},featureMembers:function(a,b){this.readChildNodes(a,b)},name:function(a,b){b.name=this.getChildValue(a)},boundedBy:function(a,b){var c={};this.readChildNodes(a,c);if(c.components&&c.components.length>0)b.bounds=c.components[0]},Point:function(a,
2036 b){var c={points:[]};this.readChildNodes(a,c);if(!b.components)b.components=[];b.components.push(c.points[0])},coordinates:function(a,b){for(var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace),d,e=c.length,f=Array(e),g=0;g<e;++g){d=c[g].split(",");f[g]=this.xy?new OpenLayers.Geometry.Point(d[0],d[1],d[2]):new OpenLayers.Geometry.Point(d[1],d[0],d[2])}b.points=f},coord:function(a,b){var c={};this.readChildNodes(a,
2037 c);if(!b.points)b.points=[];b.points.push(new OpenLayers.Geometry.Point(c.x,c.y,c.z))},X:function(a,b){b.x=this.getChildValue(a)},Y:function(a,b){b.y=this.getChildValue(a)},Z:function(a,b){b.z=this.getChildValue(a)},MultiPoint:function(a,b){var c={components:[]};this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiPoint(c.components)]},pointMember:function(a,b){this.readChildNodes(a,b)},LineString:function(a,b){var c={};this.readChildNodes(a,c);if(!b.components)b.components=[];b.components.push(new OpenLayers.Geometry.LineString(c.points))},
2038 MultiLineString:function(a,b){var c={components:[]};this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiLineString(c.components)]},lineStringMember:function(a,b){this.readChildNodes(a,b)},Polygon:function(a,b){var c={outer:null,inner:[]};this.readChildNodes(a,c);c.inner.unshift(c.outer);if(!b.components)b.components=[];b.components.push(new OpenLayers.Geometry.Polygon(c.inner))},LinearRing:function(a,b){var c={};this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.LinearRing(c.points)]},
2039 MultiPolygon:function(a,b){var c={components:[]};this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)]},polygonMember:function(a,b){this.readChildNodes(a,b)},GeometryCollection:function(a,b){var c={components:[]};this.readChildNodes(a,c);b.components=[new OpenLayers.Geometry.Collection(c.components)]},geometryMember:function(a,b){this.readChildNodes(a,b)}},feature:{"*":function(a,b){var c,d=a.localName||a.nodeName.split(":").pop();b.features?!this.singleFeatureType&&
2040 OpenLayers.Util.indexOf(this.featureType,d)!==-1?c="_typeName":d===this.featureType&&(c="_typeName"):a.childNodes.length==0||a.childNodes.length==1&&a.firstChild.nodeType==3?this.extractAttributes&&(c="_attribute"):c="_geometry";c&&this.readers.feature[c].apply(this,[a,b])},_typeName:function(a,b){var c={components:[],attributes:{}};this.readChildNodes(a,c);if(c.name)c.attributes.name=c.name;var d=new OpenLayers.Feature.Vector(c.components[0],c.attributes);if(!this.singleFeatureType){d.type=a.nodeName.split(":").pop();
2041 d.namespace=a.namespaceURI}var e=a.getAttribute("fid")||this.getAttributeNS(a,this.namespaces.gml,"id");if(e)d.fid=e;this.internalProjection&&(this.externalProjection&&d.geometry)&&d.geometry.transform(this.externalProjection,this.internalProjection);if(c.bounds)d.bounds=c.bounds;b.features.push(d)},_geometry:function(a,b){if(!this.geometryName)this.geometryName=a.nodeName.split(":").pop();this.readChildNodes(a,b)},_attribute:function(a,b){var c=a.localName||a.nodeName.split(":").pop(),d=this.getChildValue(a);
2042 b.attributes[c]=d}},wfs:{FeatureCollection:function(a,b){this.readChildNodes(a,b)}}},write:function(a){a=this.writeNode("gml:"+(OpenLayers.Util.isArray(a)?"featureMembers":"featureMember"),a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:{featureMember:function(a){var b=this.createElementNSPlus("gml:featureMember");this.writeNode("feature:_typeName",a,b);return b},MultiPoint:function(a){for(var b=
2043 this.createElementNSPlus("gml:MultiPoint"),a=a.components||[a],c=0,d=a.length;c<d;++c)this.writeNode("pointMember",a[c],b);return b},pointMember:function(a){var b=this.createElementNSPlus("gml:pointMember");this.writeNode("Point",a,b);return b},MultiLineString:function(a){for(var b=this.createElementNSPlus("gml:MultiLineString"),a=a.components||[a],c=0,d=a.length;c<d;++c)this.writeNode("lineStringMember",a[c],b);return b},lineStringMember:function(a){var b=this.createElementNSPlus("gml:lineStringMember");
2044 this.writeNode("LineString",a,b);return b},MultiPolygon:function(a){for(var b=this.createElementNSPlus("gml:MultiPolygon"),a=a.components||[a],c=0,d=a.length;c<d;++c)this.writeNode("polygonMember",a[c],b);return b},polygonMember:function(a){var b=this.createElementNSPlus("gml:polygonMember");this.writeNode("Polygon",a,b);return b},GeometryCollection:function(a){for(var b=this.createElementNSPlus("gml:GeometryCollection"),c=0,d=a.components.length;c<d;++c)this.writeNode("geometryMember",a.components[c],
2045 b);return b},geometryMember:function(a){var b=this.createElementNSPlus("gml:geometryMember"),a=this.writeNode("feature:_geometry",a);b.appendChild(a.firstChild);return b}},feature:{_typeName:function(a){var b=this.createElementNSPlus("feature:"+this.featureType,{attributes:{fid:a.fid}});a.geometry&&this.writeNode("feature:_geometry",a.geometry,b);for(var c in a.attributes){var d=a.attributes[c];d!=null&&this.writeNode("feature:_attribute",{name:c,value:d},b)}return b},_geometry:function(a){this.externalProjection&&
2046 this.internalProjection&&(a=a.clone().transform(this.internalProjection,this.externalProjection));var b=this.createElementNSPlus("feature:"+this.geometryName),a=this.writeNode("gml:"+this.geometryTypes[a.CLASS_NAME],a,b);this.srsName&&a.setAttribute("srsName",this.srsName);return b},_attribute:function(a){return this.createElementNSPlus("feature:"+a.name,{value:a.value})}},wfs:{FeatureCollection:function(a){for(var b=this.createElementNSPlus("wfs:FeatureCollection"),c=0,d=a.length;c<d;++c)this.writeNode("gml:featureMember",
2047 a[c],b);return b}}},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":"LineString","OpenLayers.Geometry.MultiLineString":"MultiLineString","OpenLayers.Geometry.Polygon":"Polygon","OpenLayers.Geometry.MultiPolygon":"MultiPolygon","OpenLayers.Geometry.Collection":"GeometryCollection"}},CLASS_NAME:"OpenLayers.Format.GML.Base"});OpenLayers.Format.GML.v3=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",curve:!1,multiCurve:!0,surface:!1,multiSurface:!0,initialize:function(a){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[a])},readers:{gml:OpenLayers.Util.applyDefaults({featureMembers:function(a,b){this.readChildNodes(a,b)},Curve:function(a,b){var c={points:[]};this.readChildNodes(a,c);b.components||
2048 (b.components=[]);b.components.push(new OpenLayers.Geometry.LineString(c.points))},segments:function(a,b){this.readChildNodes(a,b)},LineStringSegment:function(a,b){var c={};this.readChildNodes(a,c);c.points&&Array.prototype.push.apply(b.points,c.points)},pos:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(this.regExes.splitSpace),c=this.xy?new OpenLayers.Geometry.Point(c[0],c[1],c[2]):new OpenLayers.Geometry.Point(c[1],c[0],c[2]);b.points=[c]},posList:function(a,
2049 b){for(var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(this.regExes.splitSpace),d=parseInt(a.getAttribute("dimension"))||2,e,f,g,h=Array(c.length/d),i=0,j=c.length;i<j;i+=d)e=c[i],f=c[i+1],g=2==d?void 0:c[i+2],h[i/d]=this.xy?new OpenLayers.Geometry.Point(e,f,g):new OpenLayers.Geometry.Point(f,e,g);b.points=h},Surface:function(a,b){this.readChildNodes(a,b)},patches:function(a,b){this.readChildNodes(a,b)},PolygonPatch:function(a,b){this.readers.gml.Polygon.apply(this,[a,b])},exterior:function(a,
2050 b){var c={};this.readChildNodes(a,c);b.outer=c.components[0]},interior:function(a,b){var c={};this.readChildNodes(a,c);b.inner.push(c.components[0])},MultiCurve:function(a,b){var c={components:[]};this.readChildNodes(a,c);0<c.components.length&&(b.components=[new OpenLayers.Geometry.MultiLineString(c.components)])},curveMember:function(a,b){this.readChildNodes(a,b)},MultiSurface:function(a,b){var c={components:[]};this.readChildNodes(a,c);0<c.components.length&&(b.components=[new OpenLayers.Geometry.MultiPolygon(c.components)])},
2051 surfaceMember:function(a,b){this.readChildNodes(a,b)},surfaceMembers:function(a,b){this.readChildNodes(a,b)},pointMembers:function(a,b){this.readChildNodes(a,b)},lineStringMembers:function(a,b){this.readChildNodes(a,b)},polygonMembers:function(a,b){this.readChildNodes(a,b)},geometryMembers:function(a,b){this.readChildNodes(a,b)},Envelope:function(a,b){var c={points:Array(2)};this.readChildNodes(a,c);b.components||(b.components=[]);var d=c.points[0],c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,
2052 d.y,c.x,c.y))},lowerCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,[a,c]);b.points[0]=c.points[0]},upperCorner:function(a,b){var c={};this.readers.gml.pos.apply(this,[a,c]);b.points[1]=c.points[0]}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){a=this.writeNode("gml:"+(OpenLayers.Util.isArray(a)?"featureMembers":"featureMember"),a);this.setAttributeNS(a,
2053 this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({featureMembers:function(a){for(var b=this.createElementNSPlus("gml:featureMembers"),c=0,d=a.length;c<d;++c)this.writeNode("feature:_typeName",a[c],b);return b},Point:function(a){var b=this.createElementNSPlus("gml:Point");this.writeNode("pos",a,b);return b},pos:function(a){return this.createElementNSPlus("gml:pos",{value:this.xy?a.x+
2054 " "+a.y:a.y+" "+a.x})},LineString:function(a){var b=this.createElementNSPlus("gml:LineString");this.writeNode("posList",a.components,b);return b},Curve:function(a){var b=this.createElementNSPlus("gml:Curve");this.writeNode("segments",a,b);return b},segments:function(a){var b=this.createElementNSPlus("gml:segments");this.writeNode("LineStringSegment",a,b);return b},LineStringSegment:function(a){var b=this.createElementNSPlus("gml:LineStringSegment");this.writeNode("posList",a.components,b);return b},
2055 posList:function(a){for(var b=a.length,c=Array(b),d,e=0;e<b;++e)d=a[e],c[e]=this.xy?d.x+" "+d.y:d.y+" "+d.x;return this.createElementNSPlus("gml:posList",{value:c.join(" ")})},Surface:function(a){var b=this.createElementNSPlus("gml:Surface");this.writeNode("patches",a,b);return b},patches:function(a){var b=this.createElementNSPlus("gml:patches");this.writeNode("PolygonPatch",a,b);return b},PolygonPatch:function(a){var b=this.createElementNSPlus("gml:PolygonPatch",{attributes:{interpolation:"planar"}});
2056 this.writeNode("exterior",a.components[0],b);for(var c=1,d=a.components.length;c<d;++c)this.writeNode("interior",a.components[c],b);return b},Polygon:function(a){var b=this.createElementNSPlus("gml:Polygon");this.writeNode("exterior",a.components[0],b);for(var c=1,d=a.components.length;c<d;++c)this.writeNode("interior",a.components[c],b);return b},exterior:function(a){var b=this.createElementNSPlus("gml:exterior");this.writeNode("LinearRing",a,b);return b},interior:function(a){var b=this.createElementNSPlus("gml:interior");
2057 this.writeNode("LinearRing",a,b);return b},LinearRing:function(a){var b=this.createElementNSPlus("gml:LinearRing");this.writeNode("posList",a.components,b);return b},MultiCurve:function(a){for(var b=this.createElementNSPlus("gml:MultiCurve"),a=a.components||[a],c=0,d=a.length;c<d;++c)this.writeNode("curveMember",a[c],b);return b},curveMember:function(a){var b=this.createElementNSPlus("gml:curveMember");this.curve?this.writeNode("Curve",a,b):this.writeNode("LineString",a,b);return b},MultiSurface:function(a){for(var b=
2058 this.createElementNSPlus("gml:MultiSurface"),a=a.components||[a],c=0,d=a.length;c<d;++c)this.writeNode("surfaceMember",a[c],b);return b},surfaceMember:function(a){var b=this.createElementNSPlus("gml:surfaceMember");this.surface?this.writeNode("Surface",a,b):this.writeNode("Polygon",a,b);return b},Envelope:function(a){var b=this.createElementNSPlus("gml:Envelope");this.writeNode("lowerCorner",a,b);this.writeNode("upperCorner",a,b);this.srsName&&b.setAttribute("srsName",this.srsName);return b},lowerCorner:function(a){return this.createElementNSPlus("gml:lowerCorner",
2059 {value:this.xy?a.left+" "+a.bottom:a.bottom+" "+a.left})},upperCorner:function(a){return this.createElementNSPlus("gml:upperCorner",{value:this.xy?a.right+" "+a.top:a.top+" "+a.right})}},OpenLayers.Format.GML.Base.prototype.writers.gml),feature:OpenLayers.Format.GML.Base.prototype.writers.feature,wfs:OpenLayers.Format.GML.Base.prototype.writers.wfs},setGeometryTypes:function(){this.geometryTypes={"OpenLayers.Geometry.Point":"Point","OpenLayers.Geometry.MultiPoint":"MultiPoint","OpenLayers.Geometry.LineString":!0===
2060 this.curve?"Curve":"LineString","OpenLayers.Geometry.MultiLineString":!1===this.multiCurve?"MultiLineString":"MultiCurve","OpenLayers.Geometry.Polygon":!0===this.surface?"Surface":"Polygon","OpenLayers.Geometry.MultiPolygon":!1===this.multiSurface?"MultiPolygon":"MultiSurface","OpenLayers.Geometry.Collection":"GeometryCollection"}},CLASS_NAME:"OpenLayers.Format.GML.v3"});OpenLayers.Format.Filter.v1_1_0=OpenLayers.Class(OpenLayers.Format.GML.v3,OpenLayers.Format.Filter.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.1.0/filter.xsd",initialize:function(a){OpenLayers.Format.GML.v3.prototype.initialize.apply(this,[a])},readers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a,b){var c=a.getAttribute("matchCase"),c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,matchCase:!("false"===c||"0"===c)});this.readChildNodes(a,
2061 c);b.filters.push(c)},PropertyIsNotEqualTo:function(a,b){var c=a.getAttribute("matchCase"),c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO,matchCase:!("false"===c||"0"===c)});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLike:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(a,c);var d=a.getAttribute("wildCard"),e=a.getAttribute("singleChar"),f=a.getAttribute("escapeChar");c.value2regex(d,e,
2062 f);b.filters.push(c)}},OpenLayers.Format.Filter.v1.prototype.readers.ogc),gml:OpenLayers.Format.GML.v3.prototype.readers.gml,feature:OpenLayers.Format.GML.v3.prototype.readers.feature},writers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsEqualTo",{attributes:{matchCase:a.matchCase}});this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsNotEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNotEqualTo",
2063 {attributes:{matchCase:a.matchCase}});this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLike:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLike",{attributes:{matchCase:a.matchCase,wildCard:"*",singleChar:".",escapeChar:"!"}});this.writeNode("PropertyName",a,b);this.writeNode("Literal",a.regex2value(),b);return b},BBOX:function(a){var b=this.createElementNSPlus("ogc:BBOX");a.property&&this.writeNode("PropertyName",a,b);var c=this.writeNode("gml:Envelope",
2064 a.value);a.projection&&c.setAttribute("srsName",a.projection);b.appendChild(c);return b},SortBy:function(a){for(var b=this.createElementNSPlus("ogc:SortBy"),c=0,d=a.length;c<d;c++)this.writeNode("ogc:SortProperty",a[c],b);return b},SortProperty:function(a){var b=this.createElementNSPlus("ogc:SortProperty");this.writeNode("ogc:PropertyName",a,b);this.writeNode("ogc:SortOrder","DESC"==a.order?"DESC":"ASC",b);return b},SortOrder:function(a){return this.createElementNSPlus("ogc:SortOrder",{value:a})}},
2065 OpenLayers.Format.Filter.v1.prototype.writers.ogc),gml:OpenLayers.Format.GML.v3.prototype.writers.gml,feature:OpenLayers.Format.GML.v3.prototype.writers.feature},writeSpatial:function(a,b){var c=this.createElementNSPlus("ogc:"+b);this.writeNode("PropertyName",a,c);if(a.value instanceof OpenLayers.Filter.Function)this.writeNode("Function",a.value,c);else{var d;d=a.value instanceof OpenLayers.Geometry?this.writeNode("feature:_geometry",a.value).firstChild:this.writeNode("gml:Envelope",a.value);a.projection&&
2066 d.setAttribute("srsName",a.projection);c.appendChild(d)}return c},CLASS_NAME:"OpenLayers.Format.Filter.v1_1_0"});OpenLayers.Format.OWSCommon=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",getVersion:function(a){var b=this.version;b||((a=a.getAttribute("xmlns:ows"))&&"1.1"===a.substring(a.lastIndexOf("/")+1)&&(b="1.1.0"),b||(b=this.defaultVersion));return b},CLASS_NAME:"OpenLayers.Format.OWSCommon"});OpenLayers.Format.OWSCommon.v1=OpenLayers.Class(OpenLayers.Format.XML,{regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a,b){OpenLayers.Util.applyDefaults(b,this.options);var c={};this.readChildNodes(a,c);return c},readers:{ows:{Exception:function(a,b){var c={code:a.getAttribute("exceptionCode"),locator:a.getAttribute("locator"),texts:[]};b.exceptions.push(c);this.readChildNodes(a,c)},ExceptionText:function(a,b){var c=this.getChildValue(a);b.texts.push(c)},
2067 ServiceIdentification:function(a,b){b.serviceIdentification={};this.readChildNodes(a,b.serviceIdentification)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},Keywords:function(a,b){b.keywords={};this.readChildNodes(a,b.keywords)},Keyword:function(a,b){b[this.getChildValue(a)]=!0},ServiceType:function(a,b){b.serviceType={codeSpace:a.getAttribute("codeSpace"),value:this.getChildValue(a)}},ServiceTypeVersion:function(a,b){b.serviceTypeVersion=
2068 this.getChildValue(a)},Fees:function(a,b){b.fees=this.getChildValue(a)},AccessConstraints:function(a,b){b.accessConstraints=this.getChildValue(a)},ServiceProvider:function(a,b){b.serviceProvider={};this.readChildNodes(a,b.serviceProvider)},ProviderName:function(a,b){b.providerName=this.getChildValue(a)},ProviderSite:function(a,b){b.providerSite=this.getAttributeNS(a,this.namespaces.xlink,"href")},ServiceContact:function(a,b){b.serviceContact={};this.readChildNodes(a,b.serviceContact)},IndividualName:function(a,
2069 b){b.individualName=this.getChildValue(a)},PositionName:function(a,b){b.positionName=this.getChildValue(a)},ContactInfo:function(a,b){b.contactInfo={};this.readChildNodes(a,b.contactInfo)},Phone:function(a,b){b.phone={};this.readChildNodes(a,b.phone)},Voice:function(a,b){b.voice=this.getChildValue(a)},Address:function(a,b){b.address={};this.readChildNodes(a,b.address)},DeliveryPoint:function(a,b){b.deliveryPoint=this.getChildValue(a)},City:function(a,b){b.city=this.getChildValue(a)},AdministrativeArea:function(a,
2070 b){b.administrativeArea=this.getChildValue(a)},PostalCode:function(a,b){b.postalCode=this.getChildValue(a)},Country:function(a,b){b.country=this.getChildValue(a)},ElectronicMailAddress:function(a,b){b.electronicMailAddress=this.getChildValue(a)},Role:function(a,b){b.role=this.getChildValue(a)},OperationsMetadata:function(a,b){b.operationsMetadata={};this.readChildNodes(a,b.operationsMetadata)},Operation:function(a,b){var c=a.getAttribute("name");b[c]={};this.readChildNodes(a,b[c])},DCP:function(a,
2071 b){b.dcp={};this.readChildNodes(a,b.dcp)},HTTP:function(a,b){b.http={};this.readChildNodes(a,b.http)},Get:function(a,b){b.get||(b.get=[]);var c={url:this.getAttributeNS(a,this.namespaces.xlink,"href")};this.readChildNodes(a,c);b.get.push(c)},Post:function(a,b){b.post||(b.post=[]);var c={url:this.getAttributeNS(a,this.namespaces.xlink,"href")};this.readChildNodes(a,c);b.post.push(c)},Parameter:function(a,b){b.parameters||(b.parameters={});var c=a.getAttribute("name");b.parameters[c]={};this.readChildNodes(a,
2072 b.parameters[c])},Constraint:function(a,b){b.constraints||(b.constraints={});var c=a.getAttribute("name");b.constraints[c]={};this.readChildNodes(a,b.constraints[c])},Value:function(a,b){b[this.getChildValue(a)]=!0},OutputFormat:function(a,b){b.formats.push({value:this.getChildValue(a)});this.readChildNodes(a,b)},WGS84BoundingBox:function(a,b){var c={};c.crs=a.getAttribute("crs");b.BoundingBox?b.BoundingBox.push(c):(b.projection=c.crs,c=b);this.readChildNodes(a,c)},BoundingBox:function(a,b){this.readers.ows.WGS84BoundingBox.apply(this,
2073 [a,b])},LowerCorner:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace);b.left=c[0];b.bottom=c[1]},UpperCorner:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),c=c.split(this.regExes.splitSpace);b.right=c[0];b.top=c[1];b.bounds=new OpenLayers.Bounds(b.left,b.bottom,b.right,b.top);delete b.left;delete b.bottom;delete b.right;delete b.top},
2074 Language:function(a,b){b.language=this.getChildValue(a)}}},writers:{ows:{BoundingBox:function(a){var b=this.createElementNSPlus("ows:BoundingBox",{attributes:{crs:a.projection}});this.writeNode("ows:LowerCorner",a,b);this.writeNode("ows:UpperCorner",a,b);return b},LowerCorner:function(a){return this.createElementNSPlus("ows:LowerCorner",{value:a.bounds.left+" "+a.bounds.bottom})},UpperCorner:function(a){return this.createElementNSPlus("ows:UpperCorner",{value:a.bounds.right+" "+a.bounds.top})},Identifier:function(a){return this.createElementNSPlus("ows:Identifier",
2075 {value:a})},Title:function(a){return this.createElementNSPlus("ows:Title",{value:a})},Abstract:function(a){return this.createElementNSPlus("ows:Abstract",{value:a})},OutputFormat:function(a){return this.createElementNSPlus("ows:OutputFormat",{value:a})}}},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1"});OpenLayers.Format.OWSCommon.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows",xlink:"http://www.w3.org/1999/xlink"},readers:{ows:OpenLayers.Util.applyDefaults({ExceptionReport:function(a,b){b.success=!1;b.exceptionReport={version:a.getAttribute("version"),language:a.getAttribute("language"),exceptions:[]};this.readChildNodes(a,b.exceptionReport)}},OpenLayers.Format.OWSCommon.v1.prototype.readers.ows)},writers:{ows:OpenLayers.Format.OWSCommon.v1.prototype.writers.ows},
2076 CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_0_0"});OpenLayers.Format.WFST.v1_1_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_1_0,OpenLayers.Format.WFST.v1,{version:"1.1.0",schemaLocations:{wfs:"http://schemas.opengis.net/wfs/1.1.0/wfs.xsd"},initialize:function(a){OpenLayers.Format.Filter.v1_1_0.prototype.initialize.apply(this,[a]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[a])},readNode:function(a,b){return OpenLayers.Format.GML.v3.prototype.readNode.apply(this,[a,b])},readers:{wfs:OpenLayers.Util.applyDefaults({FeatureCollection:function(a,
2077 b){b.numberOfFeatures=parseInt(a.getAttribute("numberOfFeatures"));OpenLayers.Format.WFST.v1.prototype.readers.wfs.FeatureCollection.apply(this,arguments)},TransactionResponse:function(a,b){b.insertIds=[];b.success=!1;this.readChildNodes(a,b)},TransactionSummary:function(a,b){b.success=!0},InsertResults:function(a,b){this.readChildNodes(a,b)},Feature:function(a,b){var c={fids:[]};this.readChildNodes(a,c);b.insertIds.push(c.fids[0])}},OpenLayers.Format.WFST.v1.prototype.readers.wfs),gml:OpenLayers.Format.GML.v3.prototype.readers.gml,
2078 feature:OpenLayers.Format.GML.v3.prototype.readers.feature,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.readers.ogc,ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows},writers:{wfs:OpenLayers.Util.applyDefaults({GetFeature:function(a){var b=OpenLayers.Format.WFST.v1.prototype.writers.wfs.GetFeature.apply(this,arguments);a&&this.setAttributes(b,{resultType:a.resultType,startIndex:a.startIndex,count:a.count});return b},Query:function(a){var a=OpenLayers.Util.extend({featureNS:this.featureNS,
2079 featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName},a),b=a.featurePrefix,c=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(b?b+":":"")+a.featureType,srsName:a.srsName}});a.featureNS&&c.setAttribute("xmlns:"+b,a.featureNS);if(a.propertyNames)for(var b=0,d=a.propertyNames.length;b<d;b++)this.writeNode("wfs:PropertyName",{property:a.propertyNames[b]},c);a.filter&&(OpenLayers.Format.WFST.v1_1_0.prototype.setFilterProperty.call(this,a.filter),this.writeNode("ogc:Filter",
2080 a.filter,c));return c},PropertyName:function(a){return this.createElementNSPlus("wfs:PropertyName",{value:a.property})}},OpenLayers.Format.WFST.v1.prototype.writers.wfs),gml:OpenLayers.Format.GML.v3.prototype.writers.gml,feature:OpenLayers.Format.GML.v3.prototype.writers.feature,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc},CLASS_NAME:"OpenLayers.Format.WFST.v1_1_0"});OpenLayers.Protocol=OpenLayers.Class({format:null,options:null,autoDestroy:!0,defaultFilter:null,initialize:function(a){a=a||{};OpenLayers.Util.extend(this,a);this.options=a},mergeWithDefaultFilter:function(a){return a&&this.defaultFilter?new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,filters:[this.defaultFilter,a]}):a||this.defaultFilter||void 0},destroy:function(){this.format=this.options=null},read:function(a){a=a||{};a.filter=this.mergeWithDefaultFilter(a.filter)},create:function(){},
2081 update:function(){},"delete":function(){},commit:function(){},abort:function(){},createCallback:function(a,b,c){return OpenLayers.Function.bind(function(){a.apply(this,[b,c])},this)},CLASS_NAME:"OpenLayers.Protocol"});OpenLayers.Protocol.Response=OpenLayers.Class({code:null,requestType:null,last:!0,features:null,data:null,reqFeatures:null,priv:null,error:null,initialize:function(a){OpenLayers.Util.extend(this,a)},success:function(){return 0<this.code},CLASS_NAME:"OpenLayers.Protocol.Response"});
2082 OpenLayers.Protocol.Response.SUCCESS=1;OpenLayers.Protocol.Response.FAILURE=0;OpenLayers.Format.JSON=OpenLayers.Class(OpenLayers.Format,{indent:" ",space:" ",newline:"\n",level:0,pretty:!1,nativeJSON:function(){return!(!window.JSON||!("function"==typeof JSON.parse&&"function"==typeof JSON.stringify))}(),read:function(a,b){var c;if(this.nativeJSON)c=JSON.parse(a,b);else try{if(/^[\],:{}\s]*$/.test(a.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))&&(c=eval("("+a+")"),"function"===
2083 typeof b)){var d=function(a,c){if(c&&"object"===typeof c)for(var e in c)c.hasOwnProperty(e)&&(c[e]=d(e,c[e]));return b(a,c)};c=d("",c)}}catch(e){}this.keepData&&(this.data=c);return c},write:function(a,b){this.pretty=!!b;var c=null,d=typeof a;if(this.serialize[d])try{c=!this.pretty&&this.nativeJSON?JSON.stringify(a):this.serialize[d].apply(this,[a])}catch(e){OpenLayers.Console.error("Trouble serializing: "+e)}return c},writeIndent:function(){var a=[];if(this.pretty)for(var b=0;b<this.level;++b)a.push(this.indent);
2084 return a.join("")},writeNewline:function(){return this.pretty?this.newline:""},writeSpace:function(){return this.pretty?this.space:""},serialize:{object:function(a){if(null==a)return"null";if(a.constructor==Date)return this.serialize.date.apply(this,[a]);if(a.constructor==Array)return this.serialize.array.apply(this,[a]);var b=["{"];this.level+=1;var c,d,e,f=!1;for(c in a)a.hasOwnProperty(c)&&(d=OpenLayers.Format.JSON.prototype.write.apply(this,[c,this.pretty]),e=OpenLayers.Format.JSON.prototype.write.apply(this,
2085 [a[c],this.pretty]),null!=d&&null!=e&&(f&&b.push(","),b.push(this.writeNewline(),this.writeIndent(),d,":",this.writeSpace(),e),f=!0));this.level-=1;b.push(this.writeNewline(),this.writeIndent(),"}");return b.join("")},array:function(a){var b,c=["["];this.level+=1;for(var d=0,e=a.length;d<e;++d)b=OpenLayers.Format.JSON.prototype.write.apply(this,[a[d],this.pretty]),null!=b&&(0<d&&c.push(","),c.push(this.writeNewline(),this.writeIndent(),b));this.level-=1;c.push(this.writeNewline(),this.writeIndent(),
2086 "]");return c.join("")},string:function(a){var b={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return/["\\\x00-\x1f]/.test(a)?'"'+a.replace(/([\x00-\x1f\\"])/g,function(a,d){var e=b[d];if(e)return e;e=d.charCodeAt();return"\\u00"+Math.floor(e/16).toString(16)+(e%16).toString(16)})+'"':'"'+a+'"'},number:function(a){return isFinite(a)?""+a:"null"},"boolean":function(a){return""+a},date:function(a){function b(a){return 10>a?"0"+a:a}return'"'+a.getFullYear()+"-"+
2087 b(a.getMonth()+1)+"-"+b(a.getDate())+"T"+b(a.getHours())+":"+b(a.getMinutes())+":"+b(a.getSeconds())+'"'}},CLASS_NAME:"OpenLayers.Format.JSON"});OpenLayers.Format.GeoJSON=OpenLayers.Class(OpenLayers.Format.JSON,{ignoreExtraDims:!1,read:function(a,b,c){var b=b?b:"FeatureCollection",d=null,e=null;if(e="string"==typeof a?OpenLayers.Format.JSON.prototype.read.apply(this,[a,c]):a)if("string"!=typeof e.type)OpenLayers.Console.error("Bad GeoJSON - no type: "+a);else{if(this.isValidType(e,b))switch(b){case "Geometry":try{d=this.parseGeometry(e)}catch(f){OpenLayers.Console.error(f)}break;case "Feature":try{d=this.parseFeature(e),d.type="Feature"}catch(g){OpenLayers.Console.error(g)}break;
2088 case "FeatureCollection":switch(d=[],e.type){case "Feature":try{d.push(this.parseFeature(e))}catch(h){d=null,OpenLayers.Console.error(h)}break;case "FeatureCollection":a=0;for(b=e.features.length;a<b;++a)try{d.push(this.parseFeature(e.features[a]))}catch(i){d=null,OpenLayers.Console.error(i)}break;default:try{var j=this.parseGeometry(e);d.push(new OpenLayers.Feature.Vector(j))}catch(k){d=null,OpenLayers.Console.error(k)}}}}else OpenLayers.Console.error("Bad JSON: "+a);return d},isValidType:function(a,
2089 b){var c=!1;switch(b){case "Geometry":-1==OpenLayers.Util.indexOf("Point MultiPoint LineString MultiLineString Polygon MultiPolygon Box GeometryCollection".split(" "),a.type)?OpenLayers.Console.error("Unsupported geometry type: "+a.type):c=!0;break;case "FeatureCollection":c=!0;break;default:a.type==b?c=!0:OpenLayers.Console.error("Cannot convert types from "+a.type+" to "+b)}return c},parseFeature:function(a){var b,c,d;c=a.properties?a.properties:{};d=a.geometry&&a.geometry.bbox||a.bbox;try{b=this.parseGeometry(a.geometry)}catch(e){throw e;
2090 }b=new OpenLayers.Feature.Vector(b,c);d&&(b.bounds=OpenLayers.Bounds.fromArray(d));a.id&&(b.fid=a.id);return b},parseGeometry:function(a){if(null==a)return null;var b,c=!1;if("GeometryCollection"==a.type){if(!OpenLayers.Util.isArray(a.geometries))throw"GeometryCollection must have geometries array: "+a;b=a.geometries.length;for(var c=Array(b),d=0;d<b;++d)c[d]=this.parseGeometry.apply(this,[a.geometries[d]]);b=new OpenLayers.Geometry.Collection(c);c=!0}else{if(!OpenLayers.Util.isArray(a.coordinates))throw"Geometry must have coordinates array: "+
2091 a;if(!this.parseCoords[a.type.toLowerCase()])throw"Unsupported geometry type: "+a.type;try{b=this.parseCoords[a.type.toLowerCase()].apply(this,[a.coordinates])}catch(e){throw e;}}this.internalProjection&&(this.externalProjection&&!c)&&b.transform(this.externalProjection,this.internalProjection);return b},parseCoords:{point:function(a){if(!1==this.ignoreExtraDims&&2!=a.length)throw"Only 2D points are supported: "+a;return new OpenLayers.Geometry.Point(a[0],a[1])},multipoint:function(a){for(var b=[],
2092 c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.point.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiPoint(b)},linestring:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.point.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.LineString(b)},multilinestring:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.linestring.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiLineString(b)},
2093 polygon:function(a){for(var b=[],c,d,e=0,f=a.length;e<f;++e){try{d=this.parseCoords.linestring.apply(this,[a[e]])}catch(g){throw g;}c=new OpenLayers.Geometry.LinearRing(d.components);b.push(c)}return new OpenLayers.Geometry.Polygon(b)},multipolygon:function(a){for(var b=[],c=null,d=0,e=a.length;d<e;++d){try{c=this.parseCoords.polygon.apply(this,[a[d]])}catch(f){throw f;}b.push(c)}return new OpenLayers.Geometry.MultiPolygon(b)},box:function(a){if(2!=a.length)throw"GeoJSON box coordinates must have 2 elements";
2094 return new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing([new OpenLayers.Geometry.Point(a[0][0],a[0][1]),new OpenLayers.Geometry.Point(a[1][0],a[0][1]),new OpenLayers.Geometry.Point(a[1][0],a[1][1]),new OpenLayers.Geometry.Point(a[0][0],a[1][1]),new OpenLayers.Geometry.Point(a[0][0],a[0][1])])])}},write:function(a,b){var c={type:null};if(OpenLayers.Util.isArray(a)){c.type="FeatureCollection";var d=a.length;c.features=Array(d);for(var e=0;e<d;++e){var f=a[e];if(!f instanceof OpenLayers.Feature.Vector)throw"FeatureCollection only supports collections of features: "+
2095 f;c.features[e]=this.extract.feature.apply(this,[f])}}else 0==a.CLASS_NAME.indexOf("OpenLayers.Geometry")?c=this.extract.geometry.apply(this,[a]):a instanceof OpenLayers.Feature.Vector&&(c=this.extract.feature.apply(this,[a]),a.layer&&a.layer.projection&&(c.crs=this.createCRSObject(a)));return OpenLayers.Format.JSON.prototype.write.apply(this,[c,b])},createCRSObject:function(a){var a=a.layer.projection.toString(),b={};a.match(/epsg:/i)&&(a=parseInt(a.substring(a.indexOf(":")+1)),b=4326==a?{type:"name",
2096 properties:{name:"urn:ogc:def:crs:OGC:1.3:CRS84"}}:{type:"name",properties:{name:"EPSG:"+a}});return b},extract:{feature:function(a){var b=this.extract.geometry.apply(this,[a.geometry]),b={type:"Feature",properties:a.attributes,geometry:b};null!=a.fid&&(b.id=a.fid);return b},geometry:function(a){if(null==a)return null;this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b=a.CLASS_NAME.split(".")[2],a=this.extract[b.toLowerCase()].apply(this,
2097 [a]);return"Collection"==b?{type:"GeometryCollection",geometries:a}:{type:b,coordinates:a}},point:function(a){return[a.x,a.y]},multipoint:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b},linestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b},multilinestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.linestring.apply(this,
2098 [a.components[c]]));return b},polygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.linestring.apply(this,[a.components[c]]));return b},multipolygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.polygon.apply(this,[a.components[c]]));return b},collection:function(a){for(var b=a.components.length,c=Array(b),d=0;d<b;++d)c[d]=this.extract.geometry.apply(this,[a.components[d]]);return c}},CLASS_NAME:"OpenLayers.Format.GeoJSON"});OpenLayers.Protocol.Script=OpenLayers.Class(OpenLayers.Protocol,{url:null,params:null,callback:null,callbackTemplate:"OpenLayers.Protocol.Script.registry.${id}",callbackKey:"callback",callbackPrefix:"",scope:null,format:null,pendingRequests:null,srsInBBOX:!1,initialize:function(a){a=a||{};this.params={};this.pendingRequests={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);this.format||(this.format=new OpenLayers.Format.GeoJSON);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var b=
2099 new OpenLayers.Format.QueryStringFilter({srsInBBOX:this.srsInBBOX});this.filterToParams=function(a,d){return b.write(a,d)}}},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.applyDefaults(a,this.options);a.params=OpenLayers.Util.applyDefaults(a.params,this.options.params);a.filter&&this.filterToParams&&(a.params=this.filterToParams(a.filter,a.params));var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.createRequest(a.url,a.params,OpenLayers.Function.bind(function(c){b.data=
2100 c;this.handleRead(b,a)},this));b.priv=c;return b},createRequest:function(a,b,c){var c=OpenLayers.Protocol.Script.register(c),d=OpenLayers.String.format(this.callbackTemplate,{id:c}),b=OpenLayers.Util.extend({},b);b[this.callbackKey]=this.callbackPrefix+d;a=OpenLayers.Util.urlAppend(a,OpenLayers.Util.getParameterString(b));b=document.createElement("script");b.type="text/javascript";b.src=a;b.id="OpenLayers_Protocol_Script_"+c;this.pendingRequests[b.id]=b;document.getElementsByTagName("head")[0].appendChild(b);
2101 return b},destroyRequest:function(a){OpenLayers.Protocol.Script.unregister(a.id.split("_").pop());delete this.pendingRequests[a.id];a.parentNode&&a.parentNode.removeChild(a)},handleRead:function(a,b){this.handleResponse(a,b)},handleResponse:function(a,b){b.callback&&(a.data?(a.features=this.parseFeatures(a.data),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE,this.destroyRequest(a.priv),b.callback.call(b.scope,a))},parseFeatures:function(a){return this.format.read(a)},
2102 abort:function(a){if(a)this.destroyRequest(a.priv);else for(var b in this.pendingRequests)this.destroyRequest(this.pendingRequests[b])},destroy:function(){this.abort();delete this.params;delete this.format;OpenLayers.Protocol.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Protocol.Script"});(function(){var a=OpenLayers.Protocol.Script,b=0;a.registry={};a.register=function(c){var d="c"+ ++b;a.registry[d]=function(){c.apply(this,arguments)};return d};a.unregister=function(b){delete a.registry[b]}})();OpenLayers.Control.Panel=OpenLayers.Class(OpenLayers.Control,{controls:null,autoActivate:!0,defaultControl:null,saveState:!1,allowDepress:!1,activeState:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.controls=[];this.activeState={}},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments);for(var a,b=this.controls.length-1;0<=b;b--)a=this.controls[b],a.events&&
2103 a.events.un({activate:this.iconOn,deactivate:this.iconOff}),a.panel_div=null;this.activeState=null},activate:function(){if(OpenLayers.Control.prototype.activate.apply(this,arguments)){for(var a,b=0,c=this.controls.length;b<c;b++)a=this.controls[b],(a===this.defaultControl||this.saveState&&this.activeState[a.id])&&a.activate();!0===this.saveState&&(this.defaultControl=null);this.redraw();return!0}return!1},deactivate:function(){if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){for(var a,
2104 b=0,c=this.controls.length;b<c;b++)a=this.controls[b],this.activeState[a.id]=a.deactivate();this.redraw();return!0}return!1},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.outsideViewport?(this.events.attachToElement(this.div),this.events.register("buttonclick",this,this.onButtonClick)):this.map.events.register("buttonclick",this,this.onButtonClick);this.addControlsToMap(this.controls);return this.div},redraw:function(){for(var a=this.div.childNodes.length-1;0<=a;a--)this.div.removeChild(this.div.childNodes[a]);
2105 this.div.innerHTML="";if(this.active)for(var a=0,b=this.controls.length;a<b;a++)this.div.appendChild(this.controls[a].panel_div)},activateControl:function(a){if(!this.active)return!1;if(a.type==OpenLayers.Control.TYPE_BUTTON)a.trigger();else if(a.type==OpenLayers.Control.TYPE_TOGGLE)a.active?a.deactivate():a.activate();else if(this.allowDepress&&a.active)a.deactivate();else{for(var b,c=0,d=this.controls.length;c<d;c++)b=this.controls[c],b!=a&&(b.type===OpenLayers.Control.TYPE_TOOL||null==b.type)&&
2106 b.deactivate();a.activate()}},addControls:function(a){OpenLayers.Util.isArray(a)||(a=[a]);this.controls=this.controls.concat(a);for(var b=0,c=a.length;b<c;b++){var d=a[b],e=this.createControlMarkup(d);OpenLayers.Element.addClass(e,d.displayClass+"ItemInactive");OpenLayers.Element.addClass(e,"olButton");""!=d.title&&!e.title&&(e.title=d.title);d.panel_div=e}this.map&&(this.addControlsToMap(a),this.redraw())},createControlMarkup:function(){return document.createElement("div")},addControlsToMap:function(a){for(var b,
2107 c=0,d=a.length;c<d;c++)b=a[c],!0===b.autoActivate?(b.autoActivate=!1,this.map.addControl(b),b.autoActivate=!0):(this.map.addControl(b),b.deactivate()),b.events.on({activate:this.iconOn,deactivate:this.iconOff})},iconOn:function(){var a=this.panel_div;a.className=a.className.replace(RegExp("\\b("+this.displayClass+"Item)Inactive\\b"),"$1Active")},iconOff:function(){var a=this.panel_div;a.className=a.className.replace(RegExp("\\b("+this.displayClass+"Item)Active\\b"),"$1Inactive")},onButtonClick:function(a){for(var b=
2108 this.controls,a=a.buttonElement,c=b.length-1;0<=c;--c)if(b[c].panel_div===a){this.activateControl(b[c]);break}},getControlsBy:function(a,b){var c="function"==typeof b.test;return OpenLayers.Array.filter(this.controls,function(d){return d[a]==b||c&&b.test(d[a])})},getControlsByName:function(a){return this.getControlsBy("name",a)},getControlsByClass:function(a){return this.getControlsBy("CLASS_NAME",a)},CLASS_NAME:"OpenLayers.Control.Panel"});OpenLayers.Control.ZoomIn=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){this.map.zoomIn()},CLASS_NAME:"OpenLayers.Control.ZoomIn"});OpenLayers.Control.ZoomOut=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){this.map.zoomOut()},CLASS_NAME:"OpenLayers.Control.ZoomOut"});OpenLayers.Control.ZoomToMaxExtent=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){this.map&&this.map.zoomToMaxExtent()},CLASS_NAME:"OpenLayers.Control.ZoomToMaxExtent"});OpenLayers.Control.ZoomPanel=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);this.addControls([new OpenLayers.Control.ZoomIn,new OpenLayers.Control.ZoomToMaxExtent,new OpenLayers.Control.ZoomOut])},CLASS_NAME:"OpenLayers.Control.ZoomPanel"});OpenLayers.Layer.HTTPRequest=OpenLayers.Class(OpenLayers.Layer,{URL_HASH_FACTOR:(Math.sqrt(5)-1)/2,url:null,params:null,reproject:!1,initialize:function(a,b,c,d){OpenLayers.Layer.prototype.initialize.apply(this,[a,d]);this.url=b;this.params||(this.params=OpenLayers.Util.extend({},c))},destroy:function(){this.params=this.url=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.HTTPRequest(this.name,this.url,this.params,this.getOptions()));
2109 return a=OpenLayers.Layer.prototype.clone.apply(this,[a])},setUrl:function(a){this.url=a},mergeNewParams:function(a){this.params=OpenLayers.Util.extend(this.params,a);a=this.redraw();null!=this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"params"});return a},redraw:function(a){return a?this.mergeNewParams({_olSalt:Math.random()}):OpenLayers.Layer.prototype.redraw.apply(this,[])},selectUrl:function(a,b){for(var c=1,d=0,e=a.length;d<e;d++)c*=a.charCodeAt(d)*this.URL_HASH_FACTOR,
2110 c-=Math.floor(c);return b[Math.floor(c*b.length)]},getFullRequestString:function(a,b){var c=b||this.url,d=OpenLayers.Util.extend({},this.params),d=OpenLayers.Util.extend(d,a),e=OpenLayers.Util.getParameterString(d);OpenLayers.Util.isArray(c)&&(c=this.selectUrl(e,c));var e=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),f;for(f in d)f.toUpperCase()in e&&delete d[f];e=OpenLayers.Util.getParameterString(d);return OpenLayers.Util.urlAppend(c,e)},CLASS_NAME:"OpenLayers.Layer.HTTPRequest"});OpenLayers.Tile=OpenLayers.Class({events:null,eventListeners:null,id:null,layer:null,url:null,bounds:null,size:null,position:null,isLoading:!1,initialize:function(a,b,c,d,e,f){this.layer=a;this.position=b.clone();this.setBounds(c);this.url=d;e&&(this.size=e.clone());this.id=OpenLayers.Util.createUniqueID("Tile_");OpenLayers.Util.extend(this,f);this.events=new OpenLayers.Events(this);if(this.eventListeners instanceof Object)this.events.on(this.eventListeners)},unload:function(){this.isLoading&&(this.isLoading=
2111 !1,this.events.triggerEvent("unload"))},destroy:function(){this.position=this.size=this.bounds=this.layer=null;this.eventListeners&&this.events.un(this.eventListeners);this.events.destroy();this.events=this.eventListeners=null},draw:function(a){a||this.clear();var b=this.shouldDraw();b&&!a&&(b=!1!==this.events.triggerEvent("beforedraw"));return b},shouldDraw:function(){var a=!1,b=this.layer.maxExtent;if(b){var c=this.layer.map,c=c.baseLayer.wrapDateLine&&c.getMaxExtent();this.bounds.intersectsBounds(b,
2112 {inclusive:!1,worldBounds:c})&&(a=!0)}return a||this.layer.displayOutsideMaxExtent},setBounds:function(a){a=a.clone();if(this.layer.map.baseLayer.wrapDateLine)var b=this.layer.map.getMaxExtent(),c=this.layer.map.getResolution(),a=a.wrapDateLine(b,{leftTolerance:c,rightTolerance:c});this.bounds=a},moveTo:function(a,b,c){null==c&&(c=!0);this.setBounds(a);this.position=b.clone();c&&this.draw()},clear:function(){},CLASS_NAME:"OpenLayers.Tile"});OpenLayers.Tile.Image=OpenLayers.Class(OpenLayers.Tile,{url:null,imgDiv:null,frame:null,imageReloadAttempts:null,layerAlphaHack:null,asyncRequestId:null,blankImageUrl:"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAQAIBRAA7",maxGetUrlLength:null,canvasContext:null,crossOriginKeyword:null,initialize:function(a,b,c,d,e,f){OpenLayers.Tile.prototype.initialize.apply(this,arguments);this.url=d;this.layerAlphaHack=this.layer.alpha&&OpenLayers.Util.alphaHack();if(null!=this.maxGetUrlLength||
2113 this.layer.gutter||this.layerAlphaHack)this.frame=document.createElement("div"),this.frame.style.position="absolute",this.frame.style.overflow="hidden";null!=this.maxGetUrlLength&&OpenLayers.Util.extend(this,OpenLayers.Tile.Image.IFrame)},destroy:function(){this.imgDiv&&(this.clear(),this.frame=this.imgDiv=null);this.asyncRequestId=null;OpenLayers.Tile.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.prototype.draw.apply(this,arguments);a?(this.layer!=this.layer.map.baseLayer&&
2114 this.layer.reproject&&(this.bounds=this.getBoundsFromBaseLayer(this.position)),this.isLoading?this._loadEvent="reload":(this.isLoading=!0,this._loadEvent="loadstart"),this.positionTile(),this.renderTile()):this.unload();return a},renderTile:function(){this.layer.div.appendChild(this.getTile());if(this.layer.async){var a=this.asyncRequestId=(this.asyncRequestId||0)+1;this.layer.getURLasync(this.bounds,function(b){a==this.asyncRequestId&&(this.url=b,this.initImage())},this)}else this.url=this.layer.getURL(this.bounds),
2115 this.initImage()},positionTile:function(){var a=this.getTile().style,b=this.frame?this.size:this.layer.getImageSize(this.bounds);a.left=this.position.x+"%";a.top=this.position.y+"%";a.width=b.w+"%";a.height=b.h+"%"},clear:function(){OpenLayers.Tile.prototype.clear.apply(this,arguments);var a=this.imgDiv;if(a){OpenLayers.Event.stopObservingElement(a);var b=this.getTile();b.parentNode===this.layer.div&&this.layer.div.removeChild(b);this.setImgSrc();!0===this.layerAlphaHack&&(a.style.filter="");OpenLayers.Element.removeClass(a,
2116 "olImageLoadError")}this.canvasContext=null},getImage:function(){if(!this.imgDiv){this.imgDiv=document.createElement("img");this.imgDiv.className="olTileImage";this.imgDiv.galleryImg="no";var a=this.imgDiv.style;if(this.frame){var b=0,c=0;this.layer.gutter&&(b=100*(this.layer.gutter/this.layer.tileSize.w),c=100*(this.layer.gutter/this.layer.tileSize.h));a.left=-b+"%";a.top=-c+"%";a.width=2*b+100+"%";a.height=2*c+100+"%"}a.visibility="hidden";a.opacity=0;1>this.layer.opacity&&(a.filter="alpha(opacity="+
2117 100*this.layer.opacity+")");a.position="absolute";this.layerAlphaHack&&(a.paddingTop=a.height,a.height="0",a.width="100%");this.frame&&this.frame.appendChild(this.imgDiv)}return this.imgDiv},initImage:function(){this.events.triggerEvent(this._loadEvent);var a=this.getImage();if(this.url&&a.getAttribute("src")==this.url)this.onImageLoad();else{var b=OpenLayers.Function.bind(function(){OpenLayers.Event.stopObservingElement(a);OpenLayers.Event.observe(a,"load",OpenLayers.Function.bind(this.onImageLoad,
2118 this));OpenLayers.Event.observe(a,"error",OpenLayers.Function.bind(this.onImageError,this));this.imageReloadAttempts=0;this.setImgSrc(this.url)},this);a.getAttribute("src")==this.blankImageUrl?b():(OpenLayers.Event.observe(a,"load",b),OpenLayers.Event.observe(a,"error",b),this.crossOriginKeyword&&a.removeAttribute("crossorigin"),a.src=this.blankImageUrl)}},setImgSrc:function(a){var b=this.imgDiv;b.style.visibility="hidden";b.style.opacity=0;a&&(this.crossOriginKeyword&&("data:"!==a.substr(0,5)?b.setAttribute("crossorigin",
2119 this.crossOriginKeyword):b.removeAttribute("crossorigin")),b.src=a)},getTile:function(){return this.frame?this.frame:this.getImage()},createBackBuffer:function(){if(this.imgDiv&&!this.isLoading){var a;this.frame?(a=this.frame.cloneNode(!1),a.appendChild(this.imgDiv)):a=this.imgDiv;this.imgDiv=null;return a}},onImageLoad:function(){var a=this.imgDiv;OpenLayers.Event.stopObservingElement(a);a.style.visibility="inherit";a.style.opacity=this.layer.opacity;this.isLoading=!1;this.canvasContext=null;this.events.triggerEvent("loadend");
2120 if(7>parseFloat(navigator.appVersion.split("MSIE")[1])&&this.layer&&this.layer.div){var b=document.createElement("span");b.style.display="none";var c=this.layer.div;c.appendChild(b);window.setTimeout(function(){b.parentNode===c&&b.parentNode.removeChild(b)},0)}!0===this.layerAlphaHack&&(a.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+a.src+"', sizingMethod='scale')")},onImageError:function(){var a=this.imgDiv;null!=a.src&&(this.imageReloadAttempts++,this.imageReloadAttempts<=
2121 OpenLayers.IMAGE_RELOAD_ATTEMPTS?this.setImgSrc(this.layer.getURL(this.bounds)):(OpenLayers.Element.addClass(a,"olImageLoadError"),this.events.triggerEvent("loaderror"),this.onImageLoad()))},getCanvasContext:function(){if(OpenLayers.CANVAS_SUPPORTED&&this.imgDiv&&!this.isLoading){if(!this.canvasContext){var a=document.createElement("canvas");a.width=this.size.w;a.height=this.size.h;this.canvasContext=a.getContext("2d");this.canvasContext.drawImage(this.imgDiv,0,0)}return this.canvasContext}},CLASS_NAME:"OpenLayers.Tile.Image"});OpenLayers.Layer.Grid=OpenLayers.Class(OpenLayers.Layer.HTTPRequest,{tileSize:null,tileOriginCorner:"bl",tileOrigin:null,tileOptions:null,tileClass:OpenLayers.Tile.Image,grid:null,singleTile:!1,ratio:1.5,buffer:0,transitionEffect:null,numLoadingTiles:0,tileLoadingDelay:85,serverResolutions:null,moveTimerId:null,deferMoveGriddedTiles:null,tileQueueId:null,tileQueue:null,loading:!1,backBuffer:null,gridResolution:null,backBufferResolution:null,backBufferLonLat:null,backBufferTimerId:null,removeBackBufferDelay:null,
2122 className:null,initialize:function(a,b,c,d){OpenLayers.Layer.HTTPRequest.prototype.initialize.apply(this,arguments);this.grid=[];this.tileQueue=[];null===this.removeBackBufferDelay&&(this.removeBackBufferDelay=this.singleTile?0:2500);null===this.className&&(this.className=this.singleTile?"olLayerGridSingleTile":"olLayerGrid");OpenLayers.Animation.isNative||(this.deferMoveGriddedTiles=OpenLayers.Function.bind(function(){this.moveGriddedTiles(true);this.moveTimerId=null},this))},setMap:function(a){OpenLayers.Layer.HTTPRequest.prototype.setMap.call(this,
2123 a);OpenLayers.Element.addClass(this.div,this.className)},removeMap:function(){null!==this.moveTimerId&&(window.clearTimeout(this.moveTimerId),this.moveTimerId=null);this.clearTileQueue();null!==this.backBufferTimerId&&(window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null)},destroy:function(){this.removeBackBuffer();this.clearGrid();this.tileSize=this.grid=null;OpenLayers.Layer.HTTPRequest.prototype.destroy.apply(this,arguments)},clearGrid:function(){this.clearTileQueue();if(this.grid){for(var a=
2124 0,b=this.grid.length;a<b;a++)for(var c=this.grid[a],d=0,e=c.length;d<e;d++)this.destroyTile(c[d]);this.grid=[];this.gridResolution=null}},clone:function(a){null==a&&(a=new OpenLayers.Layer.Grid(this.name,this.url,this.params,this.getOptions()));a=OpenLayers.Layer.HTTPRequest.prototype.clone.apply(this,[a]);null!=this.tileSize&&(a.tileSize=this.tileSize.clone());a.grid=[];a.gridResolution=null;a.backBuffer=null;a.backBufferTimerId=null;a.tileQueue=[];a.tileQueueId=null;a.loading=!1;a.moveTimerId=null;
2125 return a},moveTo:function(a,b,c){OpenLayers.Layer.HTTPRequest.prototype.moveTo.apply(this,arguments);a=a||this.map.getExtent();if(null!=a){var d=!this.grid.length||b,e=this.getTilesBounds(),f=this.map.getResolution(),g=this.getServerResolution(f);if(this.singleTile){if(d||!c&&!e.containsBounds(a))b&&"resize"!==this.transitionEffect&&this.removeBackBuffer(),(!b||"resize"===this.transitionEffect)&&this.applyBackBuffer(g),this.initSingleTile(a)}else(d=d||!e.intersectsBounds(a,{worldBounds:this.map.baseLayer.wrapDateLine&&
2126 this.map.getMaxExtent()}),f!==g?(a=this.map.calculateBounds(null,g),d&&this.transformDiv(g/f)):(this.div.style.width="100%",this.div.style.height="100%",this.div.style.left="0%",this.div.style.top="0%"),d)?(b&&"resize"===this.transitionEffect&&this.applyBackBuffer(g),this.initGriddedTiles(a)):this.moveGriddedTiles()}},getTileData:function(a){var b=null,c=a.lon,d=a.lat,e=this.grid.length;if(this.map&&e){var f=this.map.getResolution(),a=this.tileSize.w,g=this.tileSize.h,h=this.grid[0][0].bounds,i=h.left,
2127 h=h.top;if(c<i&&this.map.baseLayer.wrapDateLine)var j=this.map.getMaxExtent().getWidth(),k=Math.ceil((i-c)/j),c=c+j*k;c=(c-i)/(f*a);d=(h-d)/(f*g);f=Math.floor(c);i=Math.floor(d);0<=i&&i<e&&(e=this.grid[i][f])&&(b={tile:e,i:Math.floor((c-f)*a),j:Math.floor((d-i)*g)})}return b},queueTileDraw:function(a){a=a.object;~OpenLayers.Util.indexOf(this.tileQueue,a)||this.tileQueue.push(a);this.tileQueueId||(this.tileQueueId=OpenLayers.Animation.start(OpenLayers.Function.bind(this.drawTileFromQueue,this),null,
2128 this.div));return!1},drawTileFromQueue:function(){0===this.tileQueue.length?this.clearTileQueue():this.tileQueue.shift().draw(!0)},clearTileQueue:function(){OpenLayers.Animation.stop(this.tileQueueId);this.tileQueueId=null;this.tileQueue=[]},destroyTile:function(a){this.removeTileMonitoringHooks(a);a.destroy()},getServerResolution:function(a){a=a||this.map.getResolution();if(this.serverResolutions&&-1===OpenLayers.Util.indexOf(this.serverResolutions,a)){var b,c;for(b=this.serverResolutions.length-
2129 1;0<=b;b--)if(c=this.serverResolutions[b],c>a){a=c;break}if(-1===b)throw"no appropriate resolution in serverResolutions";}return a},getServerZoom:function(){var a=this.getServerResolution();return this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,a):this.map.getZoomForResolution(a)+(this.zoomOffset||0)},transformDiv:function(a){this.div.style.width=100*a+"%";this.div.style.height=100*a+"%";var b=this.map.getSize(),c=parseInt(this.map.layerContainerDiv.style.left,10),d=(parseInt(this.map.layerContainerDiv.style.top,
2130 10)-b.h/2)*(a-1);this.div.style.left=(c-b.w/2)*(a-1)+"%";this.div.style.top=d+"%"},getResolutionScale:function(){return parseInt(this.div.style.width,10)/100},applyBackBuffer:function(a){null!==this.backBufferTimerId&&this.removeBackBuffer();var b=this.backBuffer;if(!b){b=this.createBackBuffer();if(!b)return;this.div.insertBefore(b,this.div.firstChild);this.backBuffer=b;var c=this.grid[0][0].bounds;this.backBufferLonLat={lon:c.left,lat:c.top};this.backBufferResolution=this.gridResolution}var c=b.style,
2131 d=this.backBufferResolution/a;c.width=100*d+"%";c.height=100*d+"%";a=this.getViewPortPxFromLonLat(this.backBufferLonLat,a);c=parseInt(this.map.layerContainerDiv.style.left,10);d=parseInt(this.map.layerContainerDiv.style.top,10);b.style.left=Math.round(a.x-c)+"%";b.style.top=Math.round(a.y-d)+"%"},createBackBuffer:function(){var a;if(0<this.grid.length){a=document.createElement("div");a.id=this.div.id+"_bb";a.className="olBackBuffer";a.style.position="absolute";a.style.width="100%";a.style.height=
2132 "100%";for(var b=0,c=this.grid.length;b<c;b++)for(var d=0,e=this.grid[b].length;d<e;d++){var f=this.grid[b][d].createBackBuffer();f&&(f.style.top=b*this.tileSize.h+"%",f.style.left=d*this.tileSize.w+"%",a.appendChild(f))}}return a},removeBackBuffer:function(){this.backBuffer&&(this.div.removeChild(this.backBuffer),this.backBufferResolution=this.backBuffer=null,null!==this.backBufferTimerId&&(window.clearTimeout(this.backBufferTimerId),this.backBufferTimerId=null))},moveByPx:function(){this.singleTile||
2133 this.moveGriddedTiles()},setTileSize:function(a){this.singleTile&&(a=this.map.getSize(),a.h=parseInt(a.h*this.ratio),a.w=parseInt(a.w*this.ratio));OpenLayers.Layer.HTTPRequest.prototype.setTileSize.apply(this,[a])},getTilesBounds:function(){var a=null,b=this.grid.length;if(b)var a=this.grid[b-1][0].bounds,b=this.grid[0].length*a.getWidth(),c=this.grid.length*a.getHeight(),a=new OpenLayers.Bounds(a.left,a.bottom,a.left+b,a.bottom+c);return a},initSingleTile:function(a){this.clearTileQueue();var b=
2134 a.getCenterLonLat(),c=a.getWidth()*this.ratio,a=a.getHeight()*this.ratio,b=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2),c=this.map.getLayerPxFromLonLat({lon:b.left,lat:b.top});this.grid.length||(this.grid[0]=[]);(a=this.grid[0][0])?a.moveTo(b,c):(a=this.addTile(b,c),this.addTileMonitoringHooks(a),a.draw(),this.grid[0][0]=a);this.removeExcessTiles(1,1);this.gridResolution=this.getServerResolution()},calculateGridLayout:function(a,b,c){var d=c*this.tileSize.w,c=c*this.tileSize.h,e=
2135 a.left-b.lon,f=Math.floor(e/d)-this.buffer,e=-(e/d-f)*this.tileSize.w,f=b.lon+f*d,a=a.top-(b.lat+c),g=Math.ceil(a/c)+this.buffer;return{tilelon:d,tilelat:c,tileoffsetlon:f,tileoffsetlat:b.lat+g*c,tileoffsetx:e,tileoffsety:-(g-a/c)*this.tileSize.h}},getTileOrigin:function(){var a=this.tileOrigin;if(!a)var a=this.getMaxExtent(),b={tl:["left","top"],tr:["right","top"],bl:["left","bottom"],br:["right","bottom"]}[this.tileOriginCorner],a=new OpenLayers.LonLat(a[b[0]],a[b[1]]);return a},initGriddedTiles:function(a){this.clearTileQueue();
2136 var b=this.map.getSize(),c=Math.ceil(b.h/this.tileSize.h)+Math.max(1,2*this.buffer),b=Math.ceil(b.w/this.tileSize.w)+Math.max(1,2*this.buffer),d=this.getTileOrigin(),e=this.getServerResolution(),d=this.calculateGridLayout(a,d,e),e=Math.round(d.tileoffsetx),f=Math.round(d.tileoffsety),g=d.tileoffsetlon,h=d.tileoffsetlat,i=d.tilelon,j=d.tilelat,k=e,l=g,m=0,n=parseInt(this.map.layerContainerDiv.style.left),o=parseInt(this.map.layerContainerDiv.style.top),d=[],p=this.map.getCenter();do{var q=this.grid[m++];
2137 q||(q=[],this.grid.push(q));var g=l,e=k,r=0;do{var s=new OpenLayers.Bounds(g,h,g+i,h+j),t=e,t=t-n,u=f,u=u-o,u=new OpenLayers.Pixel(t,u);(t=q[r++])?t.moveTo(s,u,!1):(t=this.addTile(s,u),this.addTileMonitoringHooks(t),q.push(t));s=s.getCenterLonLat();d.push({tile:t,distance:Math.pow(s.lon-p.lon,2)+Math.pow(s.lat-p.lat,2)});g+=i;e+=this.tileSize.w}while(g<=a.right+i*this.buffer||r<b);h-=j;f+=this.tileSize.h}while(h>=a.bottom-j*this.buffer||m<c);this.removeExcessTiles(m,r);this.gridResolution=this.getServerResolution();
2138 d.sort(function(a,b){return a.distance-b.distance});a=0;for(c=d.length;a<c;++a)d[a].tile.draw()},getMaxExtent:function(){return this.maxExtent},addTile:function(a,b){var c=new this.tileClass(this,b,a,null,this.tileSize,this.tileOptions);c.events.register("beforedraw",this,this.queueTileDraw);return c},addTileMonitoringHooks:function(a){a.onLoadStart=function(){!1===this.loading&&(this.loading=!0,this.events.triggerEvent("loadstart"));this.events.triggerEvent("tileloadstart",{tile:a});this.numLoadingTiles++};
2139 a.onLoadEnd=function(){this.numLoadingTiles--;this.events.triggerEvent("tileloaded",{tile:a});0===this.tileQueue.length&&0===this.numLoadingTiles&&(this.loading=!1,this.events.triggerEvent("loadend"),this.backBuffer&&(this.backBufferTimerId=window.setTimeout(OpenLayers.Function.bind(this.removeBackBuffer,this),this.removeBackBufferDelay)))};a.onLoadError=function(){this.events.triggerEvent("tileerror",{tile:a})};a.events.on({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,loaderror:a.onLoadError,
2140 scope:this})},removeTileMonitoringHooks:function(a){a.unload();a.events.un({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,loaderror:a.onLoadError,scope:this})},moveGriddedTiles:function(a){if(!a&&!OpenLayers.Animation.isNative)null!=this.moveTimerId&&window.clearTimeout(this.moveTimerId),this.moveTimerId=window.setTimeout(this.deferMoveGriddedTiles,this.tileLoadingDelay);else for(var a=this.buffer||1,b=this.getResolutionScale();;){var c=this.grid[0][0].position.x*b+parseInt(this.div.style.left,
2141 10)+parseInt(this.map.layerContainerDiv.style.left),d=this.grid[0][0].position.y*b+parseInt(this.div.style.top,10)+parseInt(this.map.layerContainerDiv.style.top),e=this.tileSize.w*b,f=this.tileSize.h*b;if(c>-e*(a-1))this.shiftColumn(!0);else if(c<-e*a)this.shiftColumn(!1);else if(d>-f*(a-1))this.shiftRow(!0);else if(d<-f*a)this.shiftRow(!1);else break}},shiftRow:function(a){for(var b=this.grid,c=b[a?0:this.grid.length-1],d=this.getServerResolution(),e=a?-this.tileSize.h:this.tileSize.h,d=d*-e,f=a?
2142 b.pop():b.shift(),g=0,h=c.length;g<h;g++){var i=c[g],j=i.bounds.clone(),i=i.position.clone();j.bottom+=d;j.top+=d;i.y+=e;f[g].moveTo(j,i)}a?b.unshift(f):b.push(f)},shiftColumn:function(a){for(var b=a?-this.tileSize.w:this.tileSize.w,c=this.getServerResolution()*b,d=0,e=this.grid.length;d<e;d++){var f=this.grid[d],g=f[a?0:f.length-1],h=g.bounds.clone(),g=g.position.clone();h.left+=c;h.right+=c;g.x+=b;var i=a?this.grid[d].pop():this.grid[d].shift();i.moveTo(h,g);a?f.unshift(i):f.push(i)}},removeExcessTiles:function(a,
2143 b){for(var c,d;this.grid.length>a;){var e=this.grid.pop();c=0;for(d=e.length;c<d;c++){var f=e[c];this.destroyTile(f)}}c=0;for(d=this.grid.length;c<d;c++)for(;this.grid[c].length>b;)e=this.grid[c],f=e.pop(),this.destroyTile(f)},onMapResize:function(){this.singleTile&&(this.clearGrid(),this.setTileSize())},getTileBounds:function(a){var b=this.maxExtent,c=this.getResolution(),d=c*this.tileSize.w,c=c*this.tileSize.h,e=this.getLonLatFromViewPortPx(a),a=b.left+d*Math.floor((e.lon-b.left)/d),b=b.bottom+
2144 c*Math.floor((e.lat-b.bottom)/c);return new OpenLayers.Bounds(a,b,a+d,b+c)},CLASS_NAME:"OpenLayers.Layer.Grid"});OpenLayers.Format.ArcXML=OpenLayers.Class(OpenLayers.Format.XML,{fontStyleKeys:"antialiasing blockout font fontcolor fontsize fontstyle glowing interval outline printmode shadow transparency".split(" "),request:null,response:null,initialize:function(a){this.request=new OpenLayers.Format.ArcXML.Request;this.response=new OpenLayers.Format.ArcXML.Response;if(a)if("feature"==a.requesttype){this.request.get_image=null;var b=this.request.get_feature.query;this.addCoordSys(b.featurecoordsys,a.featureCoordSys);
2145 this.addCoordSys(b.filtercoordsys,a.filterCoordSys);a.polygon?(b.isspatial=!0,b.spatialfilter.polygon=a.polygon):a.envelope&&(b.isspatial=!0,b.spatialfilter.envelope={minx:0,miny:0,maxx:0,maxy:0},this.parseEnvelope(b.spatialfilter.envelope,a.envelope))}else"image"==a.requesttype?(this.request.get_feature=null,b=this.request.get_image.properties,this.parseEnvelope(b.envelope,a.envelope),this.addLayers(b.layerlist,a.layers),this.addImageSize(b.imagesize,a.tileSize),this.addCoordSys(b.featurecoordsys,
2146 a.featureCoordSys),this.addCoordSys(b.filtercoordsys,a.filterCoordSys)):this.request=null;OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},parseEnvelope:function(a,b){b&&4==b.length&&(a.minx=b[0],a.miny=b[1],a.maxx=b[2],a.maxy=b[3])},addLayers:function(a,b){for(var c=0,d=b.length;c<d;c++)a.push(b[c])},addImageSize:function(a,b){null!==b&&(a.width=b.w,a.height=b.h,a.printwidth=b.w,a.printheight=b.h)},addCoordSys:function(a,b){"string"==typeof b?(a.id=parseInt(b),a.string=b):"object"==typeof b&&
2147 null!==b.proj&&(a.id=b.proj.srsProjNumber,a.string=b.proj.srsCode)},iserror:function(a){var b=null;a?(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]),a=a.documentElement.getElementsByTagName("ERROR"),b=null!==a&&0<a.length):b=""!==this.response.error;return b},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=null;a&&a.documentElement&&(b="ARCXML"==a.documentElement.nodeName?a.documentElement:a.documentElement.getElementsByTagName("ARCXML")[0]);
2148 if(!b||"parsererror"===b.firstChild.nodeName){var c,d;try{c=a.firstChild.nodeValue,d=a.firstChild.childNodes[1].firstChild.nodeValue}catch(e){}throw{message:"Error parsing the ArcXML request",error:c,source:d};}return this.parseResponse(b)},write:function(a){a||(a=this.request);var b=this.createElementNS("","ARCXML");b.setAttribute("version","1.1");var c=this.createElementNS("","REQUEST");if(null!=a.get_image){var d=this.createElementNS("","GET_IMAGE");c.appendChild(d);var e=this.createElementNS("",
2149 "PROPERTIES");d.appendChild(e);a=a.get_image.properties;null!=a.featurecoordsys&&(d=this.createElementNS("","FEATURECOORDSYS"),e.appendChild(d),0===a.featurecoordsys.id?d.setAttribute("string",a.featurecoordsys.string):d.setAttribute("id",a.featurecoordsys.id));null!=a.filtercoordsys&&(d=this.createElementNS("","FILTERCOORDSYS"),e.appendChild(d),0===a.filtercoordsys.id?d.setAttribute("string",a.filtercoordsys.string):d.setAttribute("id",a.filtercoordsys.id));null!=a.envelope&&(d=this.createElementNS("",
2150 "ENVELOPE"),e.appendChild(d),d.setAttribute("minx",a.envelope.minx),d.setAttribute("miny",a.envelope.miny),d.setAttribute("maxx",a.envelope.maxx),d.setAttribute("maxy",a.envelope.maxy));d=this.createElementNS("","IMAGESIZE");e.appendChild(d);d.setAttribute("height",a.imagesize.height);d.setAttribute("width",a.imagesize.width);if(a.imagesize.height!=a.imagesize.printheight||a.imagesize.width!=a.imagesize.printwidth)d.setAttribute("printheight",a.imagesize.printheight),d.setArrtibute("printwidth",a.imagesize.printwidth);
2151 null!=a.background&&(d=this.createElementNS("","BACKGROUND"),e.appendChild(d),d.setAttribute("color",a.background.color.r+","+a.background.color.g+","+a.background.color.b),null!==a.background.transcolor&&d.setAttribute("transcolor",a.background.transcolor.r+","+a.background.transcolor.g+","+a.background.transcolor.b));if(null!=a.layerlist&&0<a.layerlist.length){d=this.createElementNS("","LAYERLIST");e.appendChild(d);for(e=0;e<a.layerlist.length;e++){var f=this.createElementNS("","LAYERDEF");d.appendChild(f);
2152 f.setAttribute("id",a.layerlist[e].id);f.setAttribute("visible",a.layerlist[e].visible);if("object"==typeof a.layerlist[e].query){var g=a.layerlist[e].query;if(0>g.where.length)continue;var h=null,h="boolean"==typeof g.spatialfilter&&g.spatialfilter?this.createElementNS("","SPATIALQUERY"):this.createElementNS("","QUERY");h.setAttribute("where",g.where);"number"==typeof g.accuracy&&0<g.accuracy&&h.setAttribute("accuracy",g.accuracy);"number"==typeof g.featurelimit&&2E3>g.featurelimit&&h.setAttribute("featurelimit",
2153 g.featurelimit);"string"==typeof g.subfields&&"#ALL#"!=g.subfields&&h.setAttribute("subfields",g.subfields);"string"==typeof g.joinexpression&&0<g.joinexpression.length&&h.setAttribute("joinexpression",g.joinexpression);"string"==typeof g.jointables&&0<g.jointables.length&&h.setAttribute("jointables",g.jointables);f.appendChild(h)}"object"==typeof a.layerlist[e].renderer&&this.addRenderer(f,a.layerlist[e].renderer)}}}else if(null!=a.get_feature&&(d=this.createElementNS("","GET_FEATURES"),d.setAttribute("outputmode",
2154 "newxml"),d.setAttribute("checkesc","true"),a.get_feature.geometry?d.setAttribute("geometry",a.get_feature.geometry):d.setAttribute("geometry","false"),a.get_feature.compact&&d.setAttribute("compact",a.get_feature.compact),"number"==a.get_feature.featurelimit&&d.setAttribute("featurelimit",a.get_feature.featurelimit),d.setAttribute("globalenvelope","true"),c.appendChild(d),null!=a.get_feature.layer&&0<a.get_feature.layer.length&&(e=this.createElementNS("","LAYER"),e.setAttribute("id",a.get_feature.layer),
2155 d.appendChild(e)),a=a.get_feature.query,null!=a))e=null,e=a.isspatial?this.createElementNS("","SPATIALQUERY"):this.createElementNS("","QUERY"),d.appendChild(e),"number"==typeof a.accuracy&&e.setAttribute("accuracy",a.accuracy),null!=a.featurecoordsys&&(d=this.createElementNS("","FEATURECOORDSYS"),0==a.featurecoordsys.id?d.setAttribute("string",a.featurecoordsys.string):d.setAttribute("id",a.featurecoordsys.id),e.appendChild(d)),null!=a.filtercoordsys&&(d=this.createElementNS("","FILTERCOORDSYS"),
2156 0===a.filtercoordsys.id?d.setAttribute("string",a.filtercoordsys.string):d.setAttribute("id",a.filtercoordsys.id),e.appendChild(d)),0<a.buffer&&(d=this.createElementNS("","BUFFER"),d.setAttribute("distance",a.buffer),e.appendChild(d)),a.isspatial&&(d=this.createElementNS("","SPATIALFILTER"),d.setAttribute("relation",a.spatialfilter.relation),e.appendChild(d),a.spatialfilter.envelope?(f=this.createElementNS("","ENVELOPE"),f.setAttribute("minx",a.spatialfilter.envelope.minx),f.setAttribute("miny",a.spatialfilter.envelope.miny),
2157 f.setAttribute("maxx",a.spatialfilter.envelope.maxx),f.setAttribute("maxy",a.spatialfilter.envelope.maxy),d.appendChild(f)):"object"==typeof a.spatialfilter.polygon&&d.appendChild(this.writePolygonGeometry(a.spatialfilter.polygon))),null!=a.where&&0<a.where.length&&e.setAttribute("where",a.where);b.appendChild(c);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},addGroupRenderer:function(a,b){var c=this.createElementNS("","GROUPRENDERER");a.appendChild(c);for(var d=0;d<b.length;d++)this.addRenderer(c,
2158 b[d])},addRenderer:function(a,b){if(OpenLayers.Util.isArray(b))this.addGroupRenderer(a,b);else{var c=this.createElementNS("",b.type.toUpperCase()+"RENDERER");a.appendChild(c);"VALUEMAPRENDERER"==c.tagName?this.addValueMapRenderer(c,b):"VALUEMAPLABELRENDERER"==c.tagName?this.addValueMapLabelRenderer(c,b):"SIMPLELABELRENDERER"==c.tagName?this.addSimpleLabelRenderer(c,b):"SCALEDEPENDENTRENDERER"==c.tagName&&this.addScaleDependentRenderer(c,b)}},addScaleDependentRenderer:function(a,b){("string"==typeof b.lower||
2159 "number"==typeof b.lower)&&a.setAttribute("lower",b.lower);("string"==typeof b.upper||"number"==typeof b.upper)&&a.setAttribute("upper",b.upper);this.addRenderer(a,b.renderer)},addValueMapLabelRenderer:function(a,b){a.setAttribute("lookupfield",b.lookupfield);a.setAttribute("labelfield",b.labelfield);if("object"==typeof b.exacts)for(var c=0,d=b.exacts.length;c<d;c++){var e=b.exacts[c],f=this.createElementNS("","EXACT");"string"==typeof e.value&&f.setAttribute("value",e.value);"string"==typeof e.label&&
2160 f.setAttribute("label",e.label);"string"==typeof e.method&&f.setAttribute("method",e.method);a.appendChild(f);if("object"==typeof e.symbol){var g=null;"text"==e.symbol.type&&(g=this.createElementNS("","TEXTSYMBOL"));if(null!=g){for(var h=this.fontStyleKeys,i=0,j=h.length;i<j;i++){var k=h[i];e.symbol[k]&&g.setAttribute(k,e.symbol[k])}f.appendChild(g)}}}},addValueMapRenderer:function(a,b){a.setAttribute("lookupfield",b.lookupfield);if("object"==typeof b.ranges)for(var c=0,d=b.ranges.length;c<d;c++){var e=
2161 b.ranges[c],f=this.createElementNS("","RANGE");f.setAttribute("lower",e.lower);f.setAttribute("upper",e.upper);a.appendChild(f);if("object"==typeof e.symbol){var g=null;"simplepolygon"==e.symbol.type&&(g=this.createElementNS("","SIMPLEPOLYGONSYMBOL"));null!=g&&("string"==typeof e.symbol.boundarycolor&&g.setAttribute("boundarycolor",e.symbol.boundarycolor),"string"==typeof e.symbol.fillcolor&&g.setAttribute("fillcolor",e.symbol.fillcolor),"number"==typeof e.symbol.filltransparency&&g.setAttribute("filltransparency",
2162 e.symbol.filltransparency),f.appendChild(g))}}else if("object"==typeof b.exacts){c=0;for(d=b.exacts.length;c<d;c++)e=b.exacts[c],f=this.createElementNS("","EXACT"),"string"==typeof e.value&&f.setAttribute("value",e.value),"string"==typeof e.label&&f.setAttribute("label",e.label),"string"==typeof e.method&&f.setAttribute("method",e.method),a.appendChild(f),"object"==typeof e.symbol&&(g=null,"simplemarker"==e.symbol.type&&(g=this.createElementNS("","SIMPLEMARKERSYMBOL")),null!=g&&("string"==typeof e.symbol.antialiasing&&
2163 g.setAttribute("antialiasing",e.symbol.antialiasing),"string"==typeof e.symbol.color&&g.setAttribute("color",e.symbol.color),"string"==typeof e.symbol.outline&&g.setAttribute("outline",e.symbol.outline),"string"==typeof e.symbol.overlap&&g.setAttribute("overlap",e.symbol.overlap),"string"==typeof e.symbol.shadow&&g.setAttribute("shadow",e.symbol.shadow),"number"==typeof e.symbol.transparency&&g.setAttribute("transparency",e.symbol.transparency),"string"==typeof e.symbol.usecentroid&&g.setAttribute("usecentroid",
2164 e.symbol.usecentroid),"number"==typeof e.symbol.width&&g.setAttribute("width",e.symbol.width),f.appendChild(g)))}},addSimpleLabelRenderer:function(a,b){a.setAttribute("field",b.field);for(var c="featureweight howmanylabels labelbufferratio labelpriorities labelweight linelabelposition rotationalangles".split(" "),d=0,e=c.length;d<e;d++){var f=c[d];b[f]&&a.setAttribute(f,b[f])}if("text"==b.symbol.type){var g=b.symbol,h=this.createElementNS("","TEXTSYMBOL");a.appendChild(h);c=this.fontStyleKeys;d=0;
2165 for(e=c.length;d<e;d++)f=c[d],g[f]&&h.setAttribute(f,b[f])}},writePolygonGeometry:function(a){if(!(a instanceof OpenLayers.Geometry.Polygon))throw{message:"Cannot write polygon geometry to ArcXML with an "+a.CLASS_NAME+" object.",geometry:a};for(var b=this.createElementNS("","POLYGON"),c=0,d=a.components.length;c<d;c++){for(var e=a.components[c],f=this.createElementNS("","RING"),g=0,h=e.components.length;g<h;g++){var i=e.components[g],j=this.createElementNS("","POINT");j.setAttribute("x",i.x);j.setAttribute("y",
2166 i.y);f.appendChild(j)}b.appendChild(f)}return b},parseResponse:function(a){"string"==typeof a&&(a=(new OpenLayers.Format.XML).read(a));var b=new OpenLayers.Format.ArcXML.Response,c=a.getElementsByTagName("ERROR");if(null!=c&&0<c.length)b.error=this.getChildValue(c,"Unknown error.");else{c=a.getElementsByTagName("RESPONSE");if(null==c||0==c.length)return b.error="No RESPONSE tag found in ArcXML response.",b;var d=c[0].firstChild.nodeName;"#text"==d&&(d=c[0].firstChild.nextSibling.nodeName);if("IMAGE"==
2167 d)c=a.getElementsByTagName("ENVELOPE"),a=a.getElementsByTagName("OUTPUT"),null==c||0==c.length?b.error="No ENVELOPE tag found in ArcXML response.":null==a||0==a.length?b.error="No OUTPUT tag found in ArcXML response.":(c=this.parseAttributes(c[0]),d=this.parseAttributes(a[0]),b.image="string"==typeof d.type?{envelope:c,output:{type:d.type,data:this.getChildValue(a[0])}}:{envelope:c,output:d});else if("FEATURES"==d){if(a=c[0].getElementsByTagName("FEATURES"),c=a[0].getElementsByTagName("FEATURECOUNT"),
2168 b.features.featurecount=c[0].getAttribute("count"),0<b.features.featurecount){c=a[0].getElementsByTagName("ENVELOPE");b.features.envelope=this.parseAttributes(c[0],"number");a=a[0].getElementsByTagName("FEATURE");for(c=0;c<a.length;c++){for(var d=new OpenLayers.Feature.Vector,e=a[c].getElementsByTagName("FIELD"),f=0;f<e.length;f++){var g=e[f].getAttribute("name"),h=e[f].getAttribute("value");d.attributes[g]=h}e=a[c].getElementsByTagName("POLYGON");if(0<e.length){e=e[0].getElementsByTagName("RING");
2169 f=[];for(g=0;g<e.length;g++){h=[];h.push(this.parsePointGeometry(e[g]));for(var i=e[g].getElementsByTagName("HOLE"),j=0;j<i.length;j++)h.push(this.parsePointGeometry(i[j]));f.push(new OpenLayers.Geometry.Polygon(h))}d.geometry=1==f.length?f[0]:new OpenLayers.Geometry.MultiPolygon(f)}b.features.feature.push(d)}}}else b.error="Unidentified response type."}return b},parseAttributes:function(a,b){for(var c={},d=0;d<a.attributes.length;d++)c[a.attributes[d].nodeName]="number"==b?parseFloat(a.attributes[d].nodeValue):
2170 a.attributes[d].nodeValue;return c},parsePointGeometry:function(a){var b=[],c=a.getElementsByTagName("COORDS");if(0<c.length){a=this.getChildValue(c[0]);a=a.split(/;/);for(c=0;c<a.length;c++){var d=a[c].split(/ /);b.push(new OpenLayers.Geometry.Point(d[0],d[1]))}}else if(a=a.getElementsByTagName("POINT"),0<a.length)for(c=0;c<a.length;c++)b.push(new OpenLayers.Geometry.Point(parseFloat(a[c].getAttribute("x")),parseFloat(a[c].getAttribute("y"))));return new OpenLayers.Geometry.LinearRing(b)},CLASS_NAME:"OpenLayers.Format.ArcXML"});
2171 OpenLayers.Format.ArcXML.Request=OpenLayers.Class({initialize:function(){return OpenLayers.Util.extend(this,{get_image:{properties:{background:null,draw:!0,envelope:{minx:0,miny:0,maxx:0,maxy:0},featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},imagesize:{height:0,width:0,dpi:96,printheight:0,printwidth:0,scalesymbols:!1},layerlist:[],output:{baseurl:"",legendbaseurl:"",legendname:"",legendpath:"",
2172 legendurl:"",name:"",path:"",type:"jpg",url:""}}},get_feature:{layer:"",query:{isspatial:!1,featurecoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},filtercoordsys:{id:0,string:"",datumtransformid:0,datumtransformstring:""},buffer:0,where:"",spatialfilter:{relation:"envelope_intersection",envelope:null}}},environment:{separators:{cs:" ",ts:";"}},layer:[],workspaces:[]})},CLASS_NAME:"OpenLayers.Format.ArcXML.Request"});
2173 OpenLayers.Format.ArcXML.Response=OpenLayers.Class({initialize:function(){return OpenLayers.Util.extend(this,{image:{envelope:null,output:""},features:{featurecount:0,envelope:null,feature:[]},error:""})},CLASS_NAME:"OpenLayers.Format.ArcXML.Response"});OpenLayers.ProxyHost="";
2174 OpenLayers.Request={DEFAULT_CONFIG:{method:"GET",url:window.location.href,async:!0,user:void 0,password:void 0,params:null,proxy:OpenLayers.ProxyHost,headers:{},data:null,callback:function(){},success:null,failure:null,scope:null},URL_SPLIT_REGEX:/([^:]*:)\/\/([^:]*:?[^@]*@)?([^:\/\?]*):?([^\/\?]*)/,events:new OpenLayers.Events(this),makeSameOrigin:function(a,b){var c=0!==a.indexOf("http"),d=!c&&a.match(this.URL_SPLIT_REGEX);if(d){var e=window.location,c=d[1]==e.protocol&&d[3]==e.hostname,d=d[4],
2175 e=e.port;if(80!=d&&""!=d||"80"!=e&&""!=e)c=c&&d==e}c||(b?a="function"==typeof b?b(a):b+encodeURIComponent(a):OpenLayers.Console.warn(OpenLayers.i18n("proxyNeeded"),{url:a}));return a},issue:function(a){var b=OpenLayers.Util.extend(this.DEFAULT_CONFIG,{proxy:OpenLayers.ProxyHost}),a=OpenLayers.Util.applyDefaults(a,b),b=!1,c;for(c in a.headers)a.headers.hasOwnProperty(c)&&"x-requested-with"===c.toLowerCase()&&(b=!0);!1===b&&(a.headers["X-Requested-With"]="XMLHttpRequest");var d=new OpenLayers.Request.XMLHttpRequest,
2176 e=OpenLayers.Util.urlAppend(a.url,OpenLayers.Util.getParameterString(a.params||{})),e=OpenLayers.Request.makeSameOrigin(e,a.proxy);d.open(a.method,e,a.async,a.user,a.password);for(var f in a.headers)d.setRequestHeader(f,a.headers[f]);var g=this.events,h=this;d.onreadystatechange=function(){d.readyState==OpenLayers.Request.XMLHttpRequest.DONE&&!1!==g.triggerEvent("complete",{request:d,config:a,requestUrl:e})&&h.runCallbacks({request:d,config:a,requestUrl:e})};!1===a.async?d.send(a.data):window.setTimeout(function(){0!==
2177 d.readyState&&d.send(a.data)},0);return d},runCallbacks:function(a){var b=a.request,c=a.config,d=c.scope?OpenLayers.Function.bind(c.callback,c.scope):c.callback,e;c.success&&(e=c.scope?OpenLayers.Function.bind(c.success,c.scope):c.success);var f;c.failure&&(f=c.scope?OpenLayers.Function.bind(c.failure,c.scope):c.failure);"file:"==OpenLayers.Util.createUrlObject(c.url).protocol&&b.responseText&&(b.status=200);d(b);if(!b.status||200<=b.status&&300>b.status)this.events.triggerEvent("success",a),e&&e(b);
2178 if(b.status&&(200>b.status||300<=b.status))this.events.triggerEvent("failure",a),f&&f(b)},GET:function(a){a=OpenLayers.Util.extend(a,{method:"GET"});return OpenLayers.Request.issue(a)},POST:function(a){a=OpenLayers.Util.extend(a,{method:"POST"});a.headers=a.headers?a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},PUT:function(a){a=OpenLayers.Util.extend(a,{method:"PUT"});a.headers=a.headers?
2179 a.headers:{};"CONTENT-TYPE"in OpenLayers.Util.upperCaseObject(a.headers)||(a.headers["Content-Type"]="application/xml");return OpenLayers.Request.issue(a)},DELETE:function(a){a=OpenLayers.Util.extend(a,{method:"DELETE"});return OpenLayers.Request.issue(a)},HEAD:function(a){a=OpenLayers.Util.extend(a,{method:"HEAD"});return OpenLayers.Request.issue(a)},OPTIONS:function(a){a=OpenLayers.Util.extend(a,{method:"OPTIONS"});return OpenLayers.Request.issue(a)}};OpenLayers.Layer.ArcIMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{ClientVersion:"9.2",ServiceName:""},featureCoordSys:"4326",filterCoordSys:"4326",layers:null,async:!0,name:"ArcIMS",isBaseLayer:!0,DEFAULT_OPTIONS:{tileSize:new OpenLayers.Size(512,512),featureCoordSys:"4326",filterCoordSys:"4326",layers:null,isBaseLayer:!0,async:!0,name:"ArcIMS"},initialize:function(a,b,c){this.tileSize=new OpenLayers.Size(512,512);this.params=OpenLayers.Util.applyDefaults({ServiceName:c.serviceName},
2180 this.DEFAULT_PARAMS);this.options=OpenLayers.Util.applyDefaults(c,this.DEFAULT_OPTIONS);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,this.params,c]);if(this.transparent&&(this.isBaseLayer||(this.isBaseLayer=!1),"image/jpeg"==this.format))this.format=OpenLayers.Util.alphaHack()?"image/gif":"image/png";null===this.options.layers&&(this.options.layers=[])},getURL:function(a){var b="",a=this.adjustBounds(a),a=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",
2181 envelope:a.toArray(),tileSize:this.tileSize})),a=new OpenLayers.Request.POST({url:this.getFullRequestString(),data:a.write(),async:!1});if(null!=a){b=a.responseXML;if(!b||!b.documentElement)b=a.responseText;b=this.getUrlOrImage((new OpenLayers.Format.ArcXML).read(b).image.output)}return b},getURLasync:function(a,b,c){a=this.adjustBounds(a);a=new OpenLayers.Format.ArcXML(OpenLayers.Util.extend(this.options,{requesttype:"image",envelope:a.toArray(),tileSize:this.tileSize}));OpenLayers.Request.POST({url:this.getFullRequestString(),
2182 async:!0,data:a.write(),callback:function(a){var e=a.responseXML;if(!e||!e.documentElement)e=a.responseText;a=(new OpenLayers.Format.ArcXML).read(e);b.call(c,this.getUrlOrImage(a.image.output))},scope:this})},getUrlOrImage:function(a){var b="";a.url?b=a.url:a.data&&(b="data:image/"+a.type+";base64,"+a.data);return b},setLayerQuery:function(a,b){for(var c=0;c<this.options.layers.length;c++)if(a==this.options.layers[c].id){this.options.layers[c].query=b;return}this.options.layers.push({id:a,visible:!0,
2183 query:b})},getFeatureInfo:function(a,b,c){var d=c.buffer||1,e=c.callback||function(){},f=c.scope||window,g={};OpenLayers.Util.extend(g,this.options);g.requesttype="feature";a instanceof OpenLayers.LonLat?(g.polygon=null,g.envelope=[a.lon-d,a.lat-d,a.lon+d,a.lat+d]):a instanceof OpenLayers.Geometry.Polygon&&(g.envelope=null,g.polygon=a);var h=new OpenLayers.Format.ArcXML(g);OpenLayers.Util.extend(h.request.get_feature,c);h.request.get_feature.layer=b.id;"number"==typeof b.query.accuracy?h.request.get_feature.query.accuracy=
2184 b.query.accuracy:(a=this.map.getCenter(),c=this.map.getViewPortPxFromLonLat(a),c.x++,c=this.map.getLonLatFromPixel(c),h.request.get_feature.query.accuracy=c.lon-a.lon);h.request.get_feature.query.where=b.query.where;h.request.get_feature.query.spatialfilter.relation="area_intersection";OpenLayers.Request.POST({url:this.getFullRequestString({CustomService:"Query"}),data:h.write(),callback:function(a){a=h.parseResponse(a.responseText);h.iserror()?e.call(f,null):e.call(f,a.features)}})},clone:function(a){null==
2185 a&&(a=new OpenLayers.Layer.ArcIMS(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.ArcIMS"});OpenLayers.Format.OWSCommon.v1_1_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1,{namespaces:{ows:"http://www.opengis.net/ows/1.1",xlink:"http://www.w3.org/1999/xlink"},readers:{ows:OpenLayers.Util.applyDefaults({ExceptionReport:function(a,b){b.exceptionReport={version:a.getAttribute("version"),language:a.getAttribute("xml:lang"),exceptions:[]};this.readChildNodes(a,b.exceptionReport)},AllowedValues:function(a,b){b.allowedValues={};this.readChildNodes(a,b.allowedValues)},AnyValue:function(a,b){b.anyValue=
2186 !0},DataType:function(a,b){b.dataType=this.getChildValue(a)},Range:function(a,b){b.range={};this.readChildNodes(a,b.range)},MinimumValue:function(a,b){b.minValue=this.getChildValue(a)},MaximumValue:function(a,b){b.maxValue=this.getChildValue(a)},Identifier:function(a,b){b.identifier=this.getChildValue(a)},SupportedCRS:function(a,b){b.supportedCRS=this.getChildValue(a)}},OpenLayers.Format.OWSCommon.v1.prototype.readers.ows)},writers:{ows:OpenLayers.Util.applyDefaults({Range:function(a){var b=this.createElementNSPlus("ows:Range",
2187 {attributes:{"ows:rangeClosure":a.closure}});this.writeNode("ows:MinimumValue",a.minValue,b);this.writeNode("ows:MaximumValue",a.maxValue,b);return b},MinimumValue:function(a){return this.createElementNSPlus("ows:MinimumValue",{value:a})},MaximumValue:function(a){return this.createElementNSPlus("ows:MaximumValue",{value:a})},Value:function(a){return this.createElementNSPlus("ows:Value",{value:a})}},OpenLayers.Format.OWSCommon.v1.prototype.writers.ows)},CLASS_NAME:"OpenLayers.Format.OWSCommon.v1_1_0"});OpenLayers.Format.WCSGetCoverage=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",wcs:"http://www.opengis.net/wcs/1.1",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.1.2",schemaLocation:"http://www.opengis.net/wcs/1.1 http://schemas.opengis.net/wcs/1.1/wcsGetCoverage.xsd",write:function(a){a=this.writeNode("wcs:GetCoverage",
2188 a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{wcs:{GetCoverage:function(a){var b=this.createElementNSPlus("wcs:GetCoverage",{attributes:{version:a.version||this.VERSION,service:"WCS"}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("wcs:DomainSubset",a.domainSubset,b);this.writeNode("wcs:Output",a.output,b);return b},DomainSubset:function(a){var b=this.createElementNSPlus("wcs:DomainSubset",
2189 {});this.writeNode("ows:BoundingBox",a.boundingBox,b);a.temporalSubset&&this.writeNode("wcs:TemporalSubset",a.temporalSubset,b);return b},TemporalSubset:function(a){for(var b=this.createElementNSPlus("wcs:TemporalSubset",{}),c=0,d=a.timePeriods.length;c<d;++c)this.writeNode("wcs:TimePeriod",a.timePeriods[c],b);return b},TimePeriod:function(a){var b=this.createElementNSPlus("wcs:TimePeriod",{});this.writeNode("wcs:BeginPosition",a.begin,b);this.writeNode("wcs:EndPosition",a.end,b);a.resolution&&this.writeNode("wcs:TimeResolution",
2190 a.resolution,b);return b},BeginPosition:function(a){return this.createElementNSPlus("wcs:BeginPosition",{value:a})},EndPosition:function(a){return this.createElementNSPlus("wcs:EndPosition",{value:a})},TimeResolution:function(a){return this.createElementNSPlus("wcs:TimeResolution",{value:a})},Output:function(a){var b=this.createElementNSPlus("wcs:Output",{attributes:{format:a.format,store:a.store}});a.gridCRS&&this.writeNode("wcs:GridCRS",a.gridCRS,b);return b},GridCRS:function(a){var b=this.createElementNSPlus("wcs:GridCRS",
2191 {});this.writeNode("wcs:GridBaseCRS",a.baseCRS,b);a.type&&this.writeNode("wcs:GridType",a.type,b);a.origin&&this.writeNode("wcs:GridOrigin",a.origin,b);this.writeNode("wcs:GridOffsets",a.offsets,b);a.CS&&this.writeNode("wcs:GridCS",a.CS,b);return b},GridBaseCRS:function(a){return this.createElementNSPlus("wcs:GridBaseCRS",{value:a})},GridOrigin:function(a){return this.createElementNSPlus("wcs:GridOrigin",{value:a})},GridType:function(a){return this.createElementNSPlus("wcs:GridType",{value:a})},GridOffsets:function(a){return this.createElementNSPlus("wcs:GridOffsets",
2192 {value:a})},GridCS:function(a){return this.createElementNSPlus("wcs:GridCS",{value:a})}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows},CLASS_NAME:"OpenLayers.Format.WCSGetCoverage"});OpenLayers.Format.WPSExecute=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",gml:"http://www.opengis.net/gml",wps:"http://www.opengis.net/wps/1.0.0",wfs:"http://www.opengis.net/wfs",ogc:"http://www.opengis.net/ogc",wcs:"http://www.opengis.net/wcs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd",
2193 schemaLocationAttr:function(){},write:function(a){var b;window.ActiveXObject?this.xmldom=b=new ActiveXObject("Microsoft.XMLDOM"):b=document.implementation.createDocument("","",null);a=this.writeNode("wps:Execute",a,b);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{wps:{Execute:function(a){var b=this.createElementNSPlus("wps:Execute",{attributes:{version:this.VERSION,service:"WPS"}});this.writeNode("ows:Identifier",
2194 a.identifier,b);this.writeNode("wps:DataInputs",a.dataInputs,b);this.writeNode("wps:ResponseForm",a.responseForm,b);return b},ResponseForm:function(a){var b=this.createElementNSPlus("wps:ResponseForm",{});a.rawDataOutput&&this.writeNode("wps:RawDataOutput",a.rawDataOutput,b);a.responseDocument&&this.writeNode("wps:ResponseDocument",a.responseDocument,b);return b},ResponseDocument:function(a){var b=this.createElementNSPlus("wps:ResponseDocument",{attributes:{storeExecuteResponse:a.storeExecuteResponse,
2195 lineage:a.lineage,status:a.status}});a.output&&this.writeNode("wps:Output",a.output,b);return b},Output:function(a){var b=this.createElementNSPlus("wps:Output",{attributes:{asReference:a.asReference}});this.writeNode("ows:Identifier",a.identifier,b);this.writeNode("ows:Title",a.title,b);this.writeNode("ows:Abstract",a["abstract"],b);return b},RawDataOutput:function(a){var b=this.createElementNSPlus("wps:RawDataOutput",{attributes:{mimeType:a.mimeType}});this.writeNode("ows:Identifier",a.identifier,
2196 b);return b},DataInputs:function(a){for(var b=this.createElementNSPlus("wps:DataInputs",{}),c=0,d=a.length;c<d;++c)this.writeNode("wps:Input",a[c],b);return b},Input:function(a){var b=this.createElementNSPlus("wps:Input",{});this.writeNode("ows:Identifier",a.identifier,b);a.title&&this.writeNode("ows:Title",a.title,b);a.data&&this.writeNode("wps:Data",a.data,b);a.reference&&this.writeNode("wps:Reference",a.reference,b);return b},Data:function(a){var b=this.createElementNSPlus("wps:Data",{});a.literalData?
2197 this.writeNode("wps:LiteralData",a.literalData,b):a.complexData&&this.writeNode("wps:ComplexData",a.complexData,b);return b},LiteralData:function(a){return this.createElementNSPlus("wps:LiteralData",{attributes:{uom:a.uom},value:a.value})},ComplexData:function(a){var b=this.createElementNSPlus("wps:ComplexData",{attributes:{mimeType:a.mimeType,encoding:a.encoding,schema:a.schema}}),c=a.value;"string"===typeof c?b.appendChild(this.getXMLDoc().createCDATASection(a.value)):b.appendChild(c);return b},
2198 Reference:function(a){var b=this.createElementNSPlus("wps:Reference",{attributes:{mimeType:a.mimeType,"xlink:href":a.href,method:a.method,encoding:a.encoding,schema:a.schema}});a.body&&this.writeNode("wps:Body",a.body,b);return b},Body:function(a){var b=this.createElementNSPlus("wps:Body",{});a.wcs?this.writeNode("wcs:GetCoverage",a.wcs,b):a.wfs?(this.featureType=a.wfs.featureType,this.version=a.wfs.version,this.writeNode("wfs:GetFeature",a.wfs,b)):this.writeNode("wps:Execute",a,b);return b}},wcs:OpenLayers.Format.WCSGetCoverage.prototype.writers.wcs,
2199 wfs:OpenLayers.Format.WFST.v1_1_0.prototype.writers.wfs,ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc,ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.writers.ows},CLASS_NAME:"OpenLayers.Format.WPSExecute"});OpenLayers.Control.PanZoom=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,slideRatio:null,buttons:null,position:null,initialize:function(a){this.position=new OpenLayers.Pixel(OpenLayers.Control.PanZoom.X,OpenLayers.Control.PanZoom.Y);OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onButtonClick);this.removeButtons();this.position=this.buttons=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},
2200 setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.register("buttonclick",this,this.onButtonClick)},draw:function(a){OpenLayers.Control.prototype.draw.apply(this,arguments);a=this.position;this.buttons=[];var b={w:18,h:18},c=new OpenLayers.Pixel(a.x+b.w/2,a.y);this._addButton("panup","north-mini.png",c,b);a.y=c.y+b.h;this._addButton("panleft","west-mini.png",a,b);this._addButton("panright","east-mini.png",a.add(b.w,0),b);this._addButton("pandown","south-mini.png",
2201 c.add(0,2*b.h),b);this._addButton("zoomin","zoom-plus-mini.png",c.add(0,3*b.h+5),b);this._addButton("zoomworld","zoom-world-mini.png",c.add(0,4*b.h+5),b);this._addButton("zoomout","zoom-minus-mini.png",c.add(0,5*b.h+5),b);return this.div},_addButton:function(a,b,c,d){b=OpenLayers.Util.getImageLocation(b);c=OpenLayers.Util.createAlphaImageDiv(this.id+"_"+a,c,d,b,"absolute");c.style.cursor="pointer";this.div.appendChild(c);c.action=a;c.className="olButton";this.buttons.push(c);return c},_removeButton:function(a){this.div.removeChild(a);
2202 OpenLayers.Util.removeItem(this.buttons,a)},removeButtons:function(){for(var a=this.buttons.length-1;0<=a;--a)this._removeButton(this.buttons[a])},onButtonClick:function(a){switch(a.buttonElement.action){case "panup":this.map.pan(0,-this.getSlideFactor("h"));break;case "pandown":this.map.pan(0,this.getSlideFactor("h"));break;case "panleft":this.map.pan(-this.getSlideFactor("w"),0);break;case "panright":this.map.pan(this.getSlideFactor("w"),0);break;case "zoomin":this.map.zoomIn();break;case "zoomout":this.map.zoomOut();
2203 break;case "zoomworld":this.map.zoomToMaxExtent()}},getSlideFactor:function(a){return this.slideRatio?this.map.getSize()[a]*this.slideRatio:this.slideFactor},CLASS_NAME:"OpenLayers.Control.PanZoom"});OpenLayers.Control.PanZoom.X=4;OpenLayers.Control.PanZoom.Y=4;OpenLayers.Control.PanZoomBar=OpenLayers.Class(OpenLayers.Control.PanZoom,{zoomStopWidth:18,zoomStopHeight:11,slider:null,sliderEvents:null,zoombarDiv:null,zoomWorldIcon:!1,panIcons:!0,forceFixedZoomLevel:!1,mouseDragStart:null,deltaY:null,zoomStart:null,destroy:function(){this._removeZoomBar();this.map.events.un({changebaselayer:this.redraw,scope:this});OpenLayers.Control.PanZoom.prototype.destroy.apply(this,arguments);delete this.mouseDragStart;delete this.zoomStart},setMap:function(a){OpenLayers.Control.PanZoom.prototype.setMap.apply(this,
2204 arguments);this.map.events.register("changebaselayer",this,this.redraw)},redraw:function(){null!=this.div&&(this.removeButtons(),this._removeZoomBar());this.draw()},draw:function(a){OpenLayers.Control.prototype.draw.apply(this,arguments);a=this.position.clone();this.buttons=[];var b={w:18,h:18};if(this.panIcons){var c=new OpenLayers.Pixel(a.x+b.w/2,a.y),d=b.w;this.zoomWorldIcon&&(c=new OpenLayers.Pixel(a.x+b.w,a.y));this._addButton("panup","north-mini.png",c,b);a.y=c.y+b.h;this._addButton("panleft",
2205 "west-mini.png",a,b);this.zoomWorldIcon&&(this._addButton("zoomworld","zoom-world-mini.png",a.add(b.w,0),b),d*=2);this._addButton("panright","east-mini.png",a.add(d,0),b);this._addButton("pandown","south-mini.png",c.add(0,2*b.h),b);this._addButton("zoomin","zoom-plus-mini.png",c.add(0,3*b.h+5),b);c=this._addZoomBar(c.add(0,4*b.h+5));this._addButton("zoomout","zoom-minus-mini.png",c,b)}else this._addButton("zoomin","zoom-plus-mini.png",a,b),c=this._addZoomBar(a.add(0,b.h)),this._addButton("zoomout",
2206 "zoom-minus-mini.png",c,b),this.zoomWorldIcon&&(c=c.add(0,b.h+3),this._addButton("zoomworld","zoom-world-mini.png",c,b));return this.div},_addZoomBar:function(a){var b=OpenLayers.Util.getImageLocation("slider.png"),c=this.id+"_"+this.map.id,d=this.map.getNumZoomLevels()-1-this.map.getZoom(),d=OpenLayers.Util.createAlphaImageDiv(c,a.add(-1,d*this.zoomStopHeight),{w:20,h:9},b,"absolute");d.style.cursor="move";this.slider=d;this.sliderEvents=new OpenLayers.Events(this,d,null,!0,{includeXY:!0});this.sliderEvents.on({touchstart:this.zoomBarDown,
2207 touchmove:this.zoomBarDrag,touchend:this.zoomBarUp,mousedown:this.zoomBarDown,mousemove:this.zoomBarDrag,mouseup:this.zoomBarUp});var e={w:this.zoomStopWidth,h:this.zoomStopHeight*this.map.getNumZoomLevels()},b=OpenLayers.Util.getImageLocation("zoombar.png"),c=null;OpenLayers.Util.alphaHack()?(c=this.id+"_"+this.map.id,c=OpenLayers.Util.createAlphaImageDiv(c,a,{w:e.w,h:this.zoomStopHeight},b,"absolute",null,"crop"),c.style.height=e.h+"px"):c=OpenLayers.Util.createDiv("OpenLayers_Control_PanZoomBar_Zoombar"+
2208 this.map.id,a,e,b);c.style.cursor="pointer";c.className="olButton";this.zoombarDiv=c;this.div.appendChild(c);this.startTop=parseInt(c.style.top);this.div.appendChild(d);this.map.events.register("zoomend",this,this.moveZoomBar);return a=a.add(0,this.zoomStopHeight*this.map.getNumZoomLevels())},_removeZoomBar:function(){this.sliderEvents.un({touchstart:this.zoomBarDown,touchmove:this.zoomBarDrag,touchend:this.zoomBarUp,mousedown:this.zoomBarDown,mousemove:this.zoomBarDrag,mouseup:this.zoomBarUp});this.sliderEvents.destroy();
2209 this.div.removeChild(this.zoombarDiv);this.zoombarDiv=null;this.div.removeChild(this.slider);this.slider=null;this.map.events.unregister("zoomend",this,this.moveZoomBar)},onButtonClick:function(a){OpenLayers.Control.PanZoom.prototype.onButtonClick.apply(this,arguments);if(a.buttonElement===this.zoombarDiv){var b=a.buttonXY.y/this.zoomStopHeight;if(this.forceFixedZoomLevel||!this.map.fractionalZoom)b=Math.floor(b);b=this.map.getNumZoomLevels()-1-b;b=Math.min(Math.max(b,0),this.map.getNumZoomLevels()-
2210 1);this.map.zoomTo(b)}},passEventToSlider:function(a){this.sliderEvents.handleBrowserEvent(a)},zoomBarDown:function(a){if(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))this.map.events.on({touchmove:this.passEventToSlider,mousemove:this.passEventToSlider,mouseup:this.passEventToSlider,scope:this}),this.mouseDragStart=a.xy.clone(),this.zoomStart=a.xy.clone(),this.div.style.cursor="move",this.zoombarDiv.offsets=null,OpenLayers.Event.stop(a)},zoomBarDrag:function(a){if(null!=this.mouseDragStart){var b=
2211 this.mouseDragStart.y-a.xy.y,c=OpenLayers.Util.pagePosition(this.zoombarDiv);0<a.clientY-c[1]&&a.clientY-c[1]<parseInt(this.zoombarDiv.style.height)-2&&(this.slider.style.top=parseInt(this.slider.style.top)-b+"px",this.mouseDragStart=a.xy.clone());this.deltaY=this.zoomStart.y-a.xy.y;OpenLayers.Event.stop(a)}},zoomBarUp:function(a){if((OpenLayers.Event.isLeftClick(a)||"touchend"===a.type)&&this.mouseDragStart){this.div.style.cursor="";this.map.events.un({touchmove:this.passEventToSlider,mouseup:this.passEventToSlider,
2212 mousemove:this.passEventToSlider,scope:this});var b=this.map.zoom;!this.forceFixedZoomLevel&&this.map.fractionalZoom?(b+=this.deltaY/this.zoomStopHeight,b=Math.min(Math.max(b,0),this.map.getNumZoomLevels()-1)):(b+=this.deltaY/this.zoomStopHeight,b=Math.max(Math.round(b),0));this.map.zoomTo(b);this.zoomStart=this.mouseDragStart=null;this.deltaY=0;OpenLayers.Event.stop(a)}},moveZoomBar:function(){this.slider.style.top=(this.map.getNumZoomLevels()-1-this.map.getZoom())*this.zoomStopHeight+this.startTop+
2213 1+"px"},CLASS_NAME:"OpenLayers.Control.PanZoomBar"});OpenLayers.Format.WFSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",errorProperty:"service",CLASS_NAME:"OpenLayers.Format.WFSCapabilities"});OpenLayers.Format.WFSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wfs:"http://www.opengis.net/wfs",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",ows:"http://www.opengis.net/ows"},defaultPrefix:"wfs",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{wfs:{WFS_Capabilities:function(a,b){this.readChildNodes(a,b)},
2214 FeatureTypeList:function(a,b){b.featureTypeList={featureTypes:[]};this.readChildNodes(a,b.featureTypeList)},FeatureType:function(a,b){var c={};this.readChildNodes(a,c);b.featureTypes.push(c)},Name:function(a,b){var c=this.getChildValue(a);c&&(c=c.split(":"),b.name=c.pop(),0<c.length&&(b.featureNS=this.lookupNamespaceURI(a,c[0])))},Title:function(a,b){var c=this.getChildValue(a);c&&(b.title=c)},Abstract:function(a,b){var c=this.getChildValue(a);c&&(b["abstract"]=c)}}},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1"});OpenLayers.Format.WFSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},readers:{wfs:OpenLayers.Util.applyDefaults({DefaultSRS:function(a,b){var c=this.getChildValue(a);c&&(b.srs=c)}},OpenLayers.Format.WFSCapabilities.v1.prototype.readers.wfs),ows:OpenLayers.Format.OWSCommon.v1.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_1_0"});OpenLayers.Layer.Image=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!0,url:null,extent:null,size:null,tile:null,aspectRatio:null,initialize:function(a,b,c,d,e){this.url=b;this.maxExtent=this.extent=c;this.size=d;OpenLayers.Layer.prototype.initialize.apply(this,[a,e]);this.aspectRatio=this.extent.getHeight()/this.size.h/(this.extent.getWidth()/this.size.w)},destroy:function(){this.tile&&(this.removeTileMonitoringHooks(this.tile),this.tile.destroy(),this.tile=null);OpenLayers.Layer.prototype.destroy.apply(this,
2215 arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Image(this.name,this.url,this.extent,this.size,this.getOptions()));return a=OpenLayers.Layer.prototype.clone.apply(this,[a])},setMap:function(a){null==this.options.maxResolution&&(this.options.maxResolution=this.aspectRatio*this.extent.getWidth()/this.size.w);OpenLayers.Layer.prototype.setMap.apply(this,arguments)},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var d=null==this.tile;if(b||d){this.setTileSize();
2216 var e=this.map.getLayerPxFromLonLat({lon:this.extent.left,lat:this.extent.top});d?(this.tile=new OpenLayers.Tile.Image(this,e,this.extent,null,this.tileSize),this.addTileMonitoringHooks(this.tile)):(this.tile.size=this.tileSize.clone(),this.tile.position=e.clone());this.tile.draw()}},setTileSize:function(){var a=this.extent.getWidth()/this.map.getResolution(),b=this.extent.getHeight()/this.map.getResolution();this.tileSize=new OpenLayers.Size(a,b)},addTileMonitoringHooks:function(a){a.onLoadStart=
2217 function(){this.events.triggerEvent("loadstart")};a.events.register("loadstart",this,a.onLoadStart);a.onLoadEnd=function(){this.events.triggerEvent("loadend")};a.events.register("loadend",this,a.onLoadEnd);a.events.register("unload",this,a.onLoadEnd)},removeTileMonitoringHooks:function(a){a.unload();a.events.un({loadstart:a.onLoadStart,loadend:a.onLoadEnd,unload:a.onLoadEnd,scope:this})},setUrl:function(a){this.url=a;this.tile.draw()},getURL:function(){return this.url},CLASS_NAME:"OpenLayers.Layer.Image"});OpenLayers.Strategy=OpenLayers.Class({layer:null,options:null,active:null,autoActivate:!0,autoDestroy:!0,initialize:function(a){OpenLayers.Util.extend(this,a);this.options=a;this.active=!1},destroy:function(){this.deactivate();this.options=this.layer=null},setLayer:function(a){this.layer=a},activate:function(){return!this.active?this.active=!0:!1},deactivate:function(){return this.active?(this.active=!1,!0):!1},CLASS_NAME:"OpenLayers.Strategy"});OpenLayers.Strategy.Save=OpenLayers.Class(OpenLayers.Strategy,{events:null,auto:!1,timer:null,initialize:function(a){OpenLayers.Strategy.prototype.initialize.apply(this,[a]);this.events=new OpenLayers.Events(this)},activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a&&this.auto)if("number"===typeof this.auto)this.timer=window.setInterval(OpenLayers.Function.bind(this.save,this),1E3*this.auto);else this.layer.events.on({featureadded:this.triggerSave,afterfeaturemodified:this.triggerSave,
2218 scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.auto&&("number"===typeof this.auto?window.clearInterval(this.timer):this.layer.events.un({featureadded:this.triggerSave,afterfeaturemodified:this.triggerSave,scope:this}));return a},triggerSave:function(a){var b=a.feature;(b.state===OpenLayers.State.INSERT||b.state===OpenLayers.State.UPDATE||b.state===OpenLayers.State.DELETE)&&this.save([a.feature])},save:function(a){a||(a=this.layer.features);
2219 this.events.triggerEvent("start",{features:a});var b=this.layer.projection,c=this.layer.map.getProjectionObject();if(!c.equals(b)){for(var d=a.length,e=Array(d),f,g,h=0;h<d;++h)f=a[h],g=f.clone(),g.fid=f.fid,g.state=f.state,f.url&&(g.url=f.url),g._original=f,g.geometry.transform(c,b),e[h]=g;a=e}this.layer.protocol.commit(a,{callback:this.onCommit,scope:this})},onCommit:function(a){var b={response:a};if(a.success()){for(var c=a.reqFeatures,d,e=[],f=a.insertIds||[],g=0,h=0,i=c.length;h<i;++h)if(d=c[h],
2220 d=d._original||d,a=d.state)a==OpenLayers.State.DELETE?e.push(d):a==OpenLayers.State.INSERT&&(d.fid=f[g],++g),d.state=null;0<e.length&&this.layer.destroyFeatures(e);this.events.triggerEvent("success",b)}else this.events.triggerEvent("fail",b)},CLASS_NAME:"OpenLayers.Strategy.Save"});OpenLayers.Format.GPX=OpenLayers.Class(OpenLayers.Format.XML,{defaultDesc:"No description available",extractWaypoints:!0,extractTracks:!0,extractRoutes:!0,extractAttributes:!0,namespaces:{gpx:"http://www.topografix.com/GPX/1/1",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd",creator:"OpenLayers",initialize:function(a){this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,
2221 [a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=[];if(this.extractTracks)for(var c=a.getElementsByTagName("trk"),d=0,e=c.length;d<e;d++){var f={};this.extractAttributes&&(f=this.parseAttributes(c[d]));for(var g=this.getElementsByTagNameNS(c[d],c[d].namespaceURI,"trkseg"),h=0,i=g.length;h<i;h++){var j=this.extractSegment(g[h],"trkpt");b.push(new OpenLayers.Feature.Vector(j,f))}}if(this.extractRoutes){e=a.getElementsByTagName("rte");c=0;for(d=
2222 e.length;c<d;c++)f={},this.extractAttributes&&(f=this.parseAttributes(e[c])),g=this.extractSegment(e[c],"rtept"),b.push(new OpenLayers.Feature.Vector(g,f))}if(this.extractWaypoints){a=a.getElementsByTagName("wpt");c=0;for(e=a.length;c<e;c++)f={},this.extractAttributes&&(f=this.parseAttributes(a[c])),d=new OpenLayers.Geometry.Point(a[c].getAttribute("lon"),a[c].getAttribute("lat")),b.push(new OpenLayers.Feature.Vector(d,f))}if(this.internalProjection&&this.externalProjection){f=0;for(a=b.length;f<
2223 a;f++)b[f].geometry.transform(this.externalProjection,this.internalProjection)}return b},extractSegment:function(a,b){for(var c=this.getElementsByTagNameNS(a,a.namespaceURI,b),d=[],e=0,f=c.length;e<f;e++)d.push(new OpenLayers.Geometry.Point(c[e].getAttribute("lon"),c[e].getAttribute("lat")));return new OpenLayers.Geometry.LineString(d)},parseAttributes:function(a){for(var b={},a=a.firstChild,c,d;a;){if(1==a.nodeType&&a.firstChild&&(c=a.firstChild,3==c.nodeType||4==c.nodeType))d=a.prefix?a.nodeName.split(":")[1]:
2224 a.nodeName,"trkseg"!=d&&"rtept"!=d&&(b[d]=c.nodeValue);a=a.nextSibling}return b},write:function(a,b){var a=OpenLayers.Util.isArray(a)?a:[a],c=this.createElementNS(this.namespaces.gpx,"gpx");c.setAttribute("version","1.1");c.setAttribute("creator",this.creator);this.setAttributes(c,{"xsi:schemaLocation":this.schemaLocation});b&&"object"==typeof b&&c.appendChild(this.buildMetadataNode(b));for(var d=0,e=a.length;d<e;d++)c.appendChild(this.buildFeatureNode(a[d]));return OpenLayers.Format.XML.prototype.write.apply(this,
2225 [c])},buildMetadataNode:function(a){for(var b=["name","desc","author"],c=this.createElementNSPlus("gpx:metadata"),d=0;d<b.length;d++){var e=b[d];if(a[e]){var f=this.createElementNSPlus("gpx:"+e);f.appendChild(this.createTextNode(a[e]));c.appendChild(f)}}return c},buildFeatureNode:function(a){var b=a.geometry,b=b.clone();this.internalProjection&&this.externalProjection&&b.transform(this.internalProjection,this.externalProjection);if("OpenLayers.Geometry.Point"==b.CLASS_NAME){var c=this.buildWptNode(b);
2226 this.appendAttributesNode(c,a);return c}c=this.createElementNSPlus("gpx:trk");this.appendAttributesNode(c,a);for(var a=this.buildTrkSegNode(b),a=OpenLayers.Util.isArray(a)?a:[a],b=0,d=a.length;b<d;b++)c.appendChild(a[b]);return c},buildTrkSegNode:function(a){var b,c,d,e;if("OpenLayers.Geometry.LineString"==a.CLASS_NAME||"OpenLayers.Geometry.LinearRing"==a.CLASS_NAME){b=this.createElementNSPlus("gpx:trkseg");c=0;for(d=a.components.length;c<d;c++)e=a.components[c],b.appendChild(this.buildTrkPtNode(e));
2227 return b}b=[];c=0;for(d=a.components.length;c<d;c++)b.push(this.buildTrkSegNode(a.components[c]));return b},buildTrkPtNode:function(a){var b=this.createElementNSPlus("gpx:trkpt");b.setAttribute("lon",a.x);b.setAttribute("lat",a.y);return b},buildWptNode:function(a){var b=this.createElementNSPlus("gpx:wpt");b.setAttribute("lon",a.x);b.setAttribute("lat",a.y);return b},appendAttributesNode:function(a,b){var c=this.createElementNSPlus("gpx:name");c.appendChild(this.createTextNode(b.attributes.name||
2228 b.id));a.appendChild(c);c=this.createElementNSPlus("gpx:desc");c.appendChild(this.createTextNode(b.attributes.description||this.defaultDesc));a.appendChild(c)},CLASS_NAME:"OpenLayers.Format.GPX"});OpenLayers.Format.WMSDescribeLayer=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.1",getVersion:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this,arguments);if("1.1.1"==c||"1.1.0"==c)c="1.1";return c},CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer"});OpenLayers.Format.WMSDescribeLayer.v1_1=OpenLayers.Class(OpenLayers.Format.WMSDescribeLayer,{initialize:function(a){OpenLayers.Format.WMSDescribeLayer.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var a=a.documentElement.childNodes,b=[],c,d,e=0;e<a.length;++e)if(c=a[e],d=c.nodeName,"LayerDescription"==d){d=c.getAttribute("name");var f="",g="",h="";c.getAttribute("owsType")?(f=c.getAttribute("owsType"),g=c.getAttribute("owsURL")):
2229 ""!=c.getAttribute("wfs")?(f="WFS",g=c.getAttribute("wfs")):""!=c.getAttribute("wcs")&&(f="WCS",g=c.getAttribute("wcs"));c=c.getElementsByTagName("Query");0<c.length&&((h=c[0].getAttribute("typeName"))||(h=c[0].getAttribute("typename")));b.push({layerName:d,owsType:f,owsURL:g,typeName:h})}return b},CLASS_NAME:"OpenLayers.Format.WMSDescribeLayer.v1_1"});OpenLayers.Layer.XYZ=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,sphericalMercator:!1,zoomOffset:0,serverResolutions:null,initialize:function(a,b,c){if(c&&c.sphericalMercator||this.sphericalMercator)c=OpenLayers.Util.extend({projection:"EPSG:900913",numZoomLevels:19},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a||this.name,b||this.url,{},c])},clone:function(a){null==a&&(a=new OpenLayers.Layer.XYZ(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
2230 [a])},getURL:function(a){var a=this.getXYZ(a),b=this.url;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(""+a.x+a.y+a.z,b));return OpenLayers.String.format(b,a)},getXYZ:function(a){var b=this.getServerResolution(),c=Math.round((a.left-this.maxExtent.left)/(b*this.tileSize.w)),a=Math.round((this.maxExtent.top-a.top)/(b*this.tileSize.h)),b=this.getServerZoom();if(this.wrapDateLine)var d=Math.pow(2,b),c=(c%d+d)%d;return{x:c,y:a,z:b}},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,
2231 arguments);this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.bottom))},CLASS_NAME:"OpenLayers.Layer.XYZ"});OpenLayers.Layer.OSM=OpenLayers.Class(OpenLayers.Layer.XYZ,{name:"OpenStreetMap",url:["http://a.tile.openstreetmap.org/${z}/${x}/${y}.png","http://b.tile.openstreetmap.org/${z}/${x}/${y}.png","http://c.tile.openstreetmap.org/${z}/${x}/${y}.png"],attribution:"Data CC-By-SA by <a href='http://openstreetmap.org/'>OpenStreetMap</a>",sphericalMercator:!0,wrapDateLine:!0,tileOptions:null,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"},
2232 this.options&&this.options.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.OSM(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},CLASS_NAME:"OpenLayers.Layer.OSM"});OpenLayers.Renderer=OpenLayers.Class({container:null,root:null,extent:null,locked:!1,size:null,resolution:null,map:null,featureDx:0,initialize:function(a,b){this.container=OpenLayers.Util.getElement(a);OpenLayers.Util.extend(this,b)},destroy:function(){this.map=this.resolution=this.size=this.extent=this.container=null},supported:function(){return!1},setExtent:function(a,b){this.extent=a.clone();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var c=a.getWidth()/this.map.getExtent().getWidth(),
2233 a=a.scale(1/c);this.extent=a.wrapDateLine(this.map.getMaxExtent()).scale(c)}b&&(this.resolution=null);return!0},setSize:function(a){this.size=a.clone();this.resolution=null},getResolution:function(){return this.resolution=this.resolution||this.map.getResolution()},drawFeature:function(a,b){null==b&&(b=a.style);if(a.geometry){var c=a.geometry.getBounds();if(c){var d;this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&(d=this.map.getMaxExtent());c.intersectsBounds(this.extent,{worldBounds:d})?this.calculateFeatureDx(c,
2234 d):b={display:"none"};c=this.drawGeometry(a.geometry,b,a.id);if("none"!=b.display&&b.label&&!1!==c){d=a.geometry.getCentroid();if(b.labelXOffset||b.labelYOffset){var e=isNaN(b.labelXOffset)?0:b.labelXOffset,f=isNaN(b.labelYOffset)?0:b.labelYOffset,g=this.getResolution();d.move(e*g,f*g)}this.drawText(a.id,b,d)}else this.removeText(a.id);return c}}},calculateFeatureDx:function(a,b){this.featureDx=0;if(b){var c=b.getWidth();this.featureDx=Math.round(((a.left+a.right)/2-(this.extent.left+this.extent.right)/
2235 2)/c)*c}},drawGeometry:function(){},drawText:function(){},removeText:function(){},clear:function(){},getFeatureIdFromEvent:function(){},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0,c=a.length;b<c;++b){var d=a[b];this.eraseGeometry(d.geometry,d.id);this.removeText(d.id)}},eraseGeometry:function(){},moveRoot:function(){},getRenderLayerId:function(){return this.container.id},applyDefaultSymbolizer:function(a){var b=OpenLayers.Util.extend({},OpenLayers.Renderer.defaultSymbolizer);
2236 !1===a.stroke&&(delete b.strokeWidth,delete b.strokeColor);!1===a.fill&&delete b.fillColor;OpenLayers.Util.extend(b,a);return b},CLASS_NAME:"OpenLayers.Renderer"});OpenLayers.Renderer.defaultSymbolizer={fillColor:"#000000",strokeColor:"#000000",strokeWidth:2,fillOpacity:1,strokeOpacity:1,pointRadius:0,labelAlign:"cm"};
2237 OpenLayers.Renderer.symbol={star:[350,75,379,161,469,161,397,215,423,301,350,250,277,301,303,215,231,161,321,161,350,75],cross:[4,0,6,0,6,4,10,4,10,6,6,6,6,10,4,10,4,6,0,6,0,4,4,4,4,0],x:[0,0,25,0,50,35,75,0,100,0,65,50,100,100,75,100,50,65,25,100,0,100,35,50,0,0],square:[0,0,0,1,1,1,1,0,0,0],triangle:[0,10,10,10,5,0,0,10]};OpenLayers.Renderer.Canvas=OpenLayers.Class(OpenLayers.Renderer,{hitDetection:!0,hitOverflow:0,canvas:null,features:null,pendingRedraw:!1,cachedSymbolBounds:{},initialize:function(a,b){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.root=document.createElement("canvas");this.container.appendChild(this.root);this.canvas=this.root.getContext("2d");this.features={};this.hitDetection&&(this.hitCanvas=document.createElement("canvas"),this.hitContext=this.hitCanvas.getContext("2d"))},
2238 setExtent:function(){OpenLayers.Renderer.prototype.setExtent.apply(this,arguments);return!1},eraseGeometry:function(a,b){this.eraseFeatures(this.features[b][0])},supported:function(){return OpenLayers.CANVAS_SUPPORTED},setSize:function(a){this.size=a.clone();var b=this.root;b.style.width=a.w+"px";b.style.height=a.h+"px";b.width=a.w;b.height=a.h;this.resolution=null;this.hitDetection&&(b=this.hitCanvas,b.style.width=a.w+"px",b.style.height=a.h+"px",b.width=a.w,b.height=a.h)},drawFeature:function(a,
2239 b){var c;if(a.geometry){b=this.applyDefaultSymbolizer(b||a.style);c=a.geometry.getBounds();var d;this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&(d=this.map.getMaxExtent());d=c&&c.intersectsBounds(this.extent,{worldBounds:d});(c="none"!==b.display&&!!c&&d)?this.features[a.id]=[a,b]:delete this.features[a.id];this.pendingRedraw=!0}this.pendingRedraw&&!this.locked&&(this.redraw(),this.pendingRedraw=!1);return c},drawGeometry:function(a,b,c){var d=a.CLASS_NAME;if("OpenLayers.Geometry.Collection"==
2240 d||"OpenLayers.Geometry.MultiPoint"==d||"OpenLayers.Geometry.MultiLineString"==d||"OpenLayers.Geometry.MultiPolygon"==d)for(d=0;d<a.components.length;d++)this.drawGeometry(a.components[d],b,c);else switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":this.drawPoint(a,b,c);break;case "OpenLayers.Geometry.LineString":this.drawLineString(a,b,c);break;case "OpenLayers.Geometry.LinearRing":this.drawLinearRing(a,b,c);break;case "OpenLayers.Geometry.Polygon":this.drawPolygon(a,b,c)}},drawExternalGraphic:function(a,
2241 b,c){var d=new Image;b.graphicTitle&&(d.title=b.graphicTitle);var e=b.graphicWidth||b.graphicHeight,f=b.graphicHeight||b.graphicWidth,e=e?e:2*b.pointRadius,f=f?f:2*b.pointRadius,g=void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*e),h=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*f),i=b.graphicOpacity||b.fillOpacity;d.onload=OpenLayers.Function.bind(function(){if(this.features[c]){var b=this.getLocalXY(a),k=b[0],b=b[1];if(!isNaN(k)&&!isNaN(b)){var k=k+g|0,b=b+h|0,l=this.canvas;l.globalAlpha=i;var m=
2242 OpenLayers.Renderer.Canvas.drawImageScaleFactor||(OpenLayers.Renderer.Canvas.drawImageScaleFactor=/android 2.1/.test(navigator.userAgent.toLowerCase())?320/window.screen.width:1);l.drawImage(d,k*m,b*m,e*m,f*m);if(this.hitDetection){this.setHitContextStyle("fill",c);this.hitContext.fillRect(k,b,e,f)}}}},this);d.src=b.externalGraphic},drawNamedSymbol:function(a,b,c){var d,e,f,g;f=Math.PI/180;var h=OpenLayers.Renderer.symbol[b.graphicName];if(!h)throw Error(b.graphicName+" is not a valid symbol name");
2243 if(h.length&&!(2>h.length)&&(a=this.getLocalXY(a),e=a[0],g=a[1],!isNaN(e)&&!isNaN(g))){this.canvas.lineCap="round";this.canvas.lineJoin="round";this.hitDetection&&(this.hitContext.lineCap="round",this.hitContext.lineJoin="round");if(b.graphicName in this.cachedSymbolBounds)d=this.cachedSymbolBounds[b.graphicName];else{d=new OpenLayers.Bounds;for(a=0;a<h.length;a+=2)d.extend(new OpenLayers.LonLat(h[a],h[a+1]));this.cachedSymbolBounds[b.graphicName]=d}this.canvas.save();this.hitDetection&&this.hitContext.save();
2244 this.canvas.translate(e,g);this.hitDetection&&this.hitContext.translate(e,g);a=f*b.rotation;isNaN(a)||(this.canvas.rotate(a),this.hitDetection&&this.hitContext.rotate(a));f=2*b.pointRadius/Math.max(d.getWidth(),d.getHeight());this.canvas.scale(f,f);this.hitDetection&&this.hitContext.scale(f,f);a=d.getCenterLonLat().lon;d=d.getCenterLonLat().lat;this.canvas.translate(-a,-d);this.hitDetection&&this.hitContext.translate(-a,-d);g=b.strokeWidth;b.strokeWidth=g/f;if(!1!==b.fill){this.setCanvasStyle("fill",
2245 b);this.canvas.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.canvas.lineTo(d,e);this.canvas.closePath();this.canvas.fill();if(this.hitDetection){this.setHitContextStyle("fill",c,b);this.hitContext.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.hitContext.lineTo(d,e);this.hitContext.closePath();this.hitContext.fill()}}if(!1!==b.stroke){this.setCanvasStyle("stroke",b);this.canvas.beginPath();for(a=0;a<h.length;a+=2)d=h[a],
2246 e=h[a+1],0==a&&this.canvas.moveTo(d,e),this.canvas.lineTo(d,e);this.canvas.closePath();this.canvas.stroke();if(this.hitDetection){this.setHitContextStyle("stroke",c,b,f);this.hitContext.beginPath();for(a=0;a<h.length;a+=2)d=h[a],e=h[a+1],0==a&&this.hitContext.moveTo(d,e),this.hitContext.lineTo(d,e);this.hitContext.closePath();this.hitContext.stroke()}}b.strokeWidth=g;this.canvas.restore();this.hitDetection&&this.hitContext.restore();this.setCanvasStyle("reset")}},setCanvasStyle:function(a,b){"fill"===
2247 a?(this.canvas.globalAlpha=b.fillOpacity,this.canvas.fillStyle=b.fillColor):"stroke"===a?(this.canvas.globalAlpha=b.strokeOpacity,this.canvas.strokeStyle=b.strokeColor,this.canvas.lineWidth=b.strokeWidth):(this.canvas.globalAlpha=0,this.canvas.lineWidth=1)},featureIdToHex:function(a){a=Number(a.split("_").pop())+1;16777216<=a&&(this.hitOverflow=a-16777215,a=a%16777216+1);var a="000000"+a.toString(16),b=a.length;return a="#"+a.substring(b-6,b)},setHitContextStyle:function(a,b,c,d){b=this.featureIdToHex(b);
2248 "fill"==a?(this.hitContext.globalAlpha=1,this.hitContext.fillStyle=b):"stroke"==a?(this.hitContext.globalAlpha=1,this.hitContext.strokeStyle=b,"undefined"===typeof d?this.hitContext.lineWidth=c.strokeWidth+2:isNaN(d)||(this.hitContext.lineWidth=c.strokeWidth+2/d)):(this.hitContext.globalAlpha=0,this.hitContext.lineWidth=1)},drawPoint:function(a,b,c){if(!1!==b.graphic)if(b.externalGraphic)this.drawExternalGraphic(a,b,c);else if(b.graphicName&&"circle"!=b.graphicName)this.drawNamedSymbol(a,b,c);else{var d=
2249 this.getLocalXY(a),a=d[0],d=d[1];if(!isNaN(a)&&!isNaN(d)){var e=2*Math.PI,f=b.pointRadius;!1!==b.fill&&(this.setCanvasStyle("fill",b),this.canvas.beginPath(),this.canvas.arc(a,d,f,0,e,!0),this.canvas.fill(),this.hitDetection&&(this.setHitContextStyle("fill",c,b),this.hitContext.beginPath(),this.hitContext.arc(a,d,f,0,e,!0),this.hitContext.fill()));!1!==b.stroke&&(this.setCanvasStyle("stroke",b),this.canvas.beginPath(),this.canvas.arc(a,d,f,0,e,!0),this.canvas.stroke(),this.hitDetection&&(this.setHitContextStyle("stroke",
2250 c,b),this.hitContext.beginPath(),this.hitContext.arc(a,d,f,0,e,!0),this.hitContext.stroke()),this.setCanvasStyle("reset"))}}},drawLineString:function(a,b,c){b=OpenLayers.Util.applyDefaults({fill:!1},b);this.drawLinearRing(a,b,c)},drawLinearRing:function(a,b,c){!1!==b.fill&&(this.setCanvasStyle("fill",b),this.renderPath(this.canvas,a,b,c,"fill"),this.hitDetection&&(this.setHitContextStyle("fill",c,b),this.renderPath(this.hitContext,a,b,c,"fill")));!1!==b.stroke&&(this.setCanvasStyle("stroke",b),this.renderPath(this.canvas,
2251 a,b,c,"stroke"),this.hitDetection&&(this.setHitContextStyle("stroke",c,b),this.renderPath(this.hitContext,a,b,c,"stroke")));this.setCanvasStyle("reset")},renderPath:function(a,b,c,d,e){b=b.components;c=b.length;a.beginPath();var d=this.getLocalXY(b[0]),f=d[1];if(!isNaN(d[0])&&!isNaN(f)){a.moveTo(d[0],d[1]);for(d=1;d<c;++d)f=this.getLocalXY(b[d]),a.lineTo(f[0],f[1]);"fill"===e?a.fill():a.stroke()}},drawPolygon:function(a,b,c){var a=a.components,d=a.length;this.drawLinearRing(a[0],b,c);for(var e=1;e<
2252 d;++e)this.canvas.globalCompositeOperation="destination-out",this.hitDetection&&(this.hitContext.globalCompositeOperation="destination-out"),this.drawLinearRing(a[e],OpenLayers.Util.applyDefaults({stroke:!1,fillOpacity:1},b),c),this.canvas.globalCompositeOperation="source-over",this.hitDetection&&(this.hitContext.globalCompositeOperation="source-over"),this.drawLinearRing(a[e],OpenLayers.Util.applyDefaults({fill:!1},b),c)},drawText:function(a,b){var c=this.getLocalXY(a);this.setCanvasStyle("reset");
2253 this.canvas.fillStyle=b.fontColor;this.canvas.globalAlpha=b.fontOpacity||1;var d=[b.fontStyle?b.fontStyle:"normal","normal",b.fontWeight?b.fontWeight:"normal",b.fontSize?b.fontSize:"1em",b.fontFamily?b.fontFamily:"sans-serif"].join(" "),e=b.label.split("\n"),f=e.length;if(this.canvas.fillText){this.canvas.font=d;this.canvas.textAlign=OpenLayers.Renderer.Canvas.LABEL_ALIGN[b.labelAlign[0]]||"center";this.canvas.textBaseline=OpenLayers.Renderer.Canvas.LABEL_ALIGN[b.labelAlign[1]]||"middle";var g=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[1]];
2254 null==g&&(g=-0.5);d=this.canvas.measureText("Mg").height||this.canvas.measureText("xx").width;c[1]+=d*g*(f-1);for(g=0;g<f;g++)b.labelOutlineWidth&&(this.canvas.save(),this.canvas.strokeStyle=b.labelOutlineColor,this.canvas.lineWidth=b.labelOutlineWidth,this.canvas.strokeText(e[g],c[0],c[1]+d*g+1),this.canvas.restore()),this.canvas.fillText(e[g],c[0],c[1]+d*g)}else if(this.canvas.mozDrawText){this.canvas.mozTextStyle=d;var h=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[0]];null==h&&(h=-0.5);
2255 g=OpenLayers.Renderer.Canvas.LABEL_FACTOR[b.labelAlign[1]];null==g&&(g=-0.5);d=this.canvas.mozMeasureText("xx");c[1]+=d*(1+g*f);for(g=0;g<f;g++){var i=c[0]+h*this.canvas.mozMeasureText(e[g]),j=c[1]+g*d;this.canvas.translate(i,j);this.canvas.mozDrawText(e[g]);this.canvas.translate(-i,-j)}}this.setCanvasStyle("reset")},getLocalXY:function(a){var b=this.getResolution(),c=this.extent;return[(a.x-this.featureDx)/b+-c.left/b,c.top/b-a.y/b]},clear:function(){var a=this.root.height,b=this.root.width;this.canvas.clearRect(0,
2256 0,b,a);this.features={};this.hitDetection&&this.hitContext.clearRect(0,0,b,a)},getFeatureIdFromEvent:function(a){var b;if(this.hitDetection&&"none"!==this.root.style.display&&!this.map.dragging&&(a=a.xy,a=this.hitContext.getImageData(a.x|0,a.y|0,1,1).data,255===a[3]&&(a=a[2]+256*(a[1]+256*a[0])))){a="OpenLayers.Feature.Vector_"+(a-1+this.hitOverflow);try{b=this.features[a][0]}catch(c){}}return b},eraseFeatures:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=0;b<a.length;++b)delete this.features[a[b].id];
2257 this.redraw()},redraw:function(){if(!this.locked){var a=this.root.height,b=this.root.width;this.canvas.clearRect(0,0,b,a);this.hitDetection&&this.hitContext.clearRect(0,0,b,a);var a=[],c,d,e=this.map.baseLayer&&this.map.baseLayer.wrapDateLine&&this.map.getMaxExtent(),f;for(f in this.features)this.features.hasOwnProperty(f)&&(b=this.features[f][0],c=b.geometry,this.calculateFeatureDx(c.getBounds(),e),d=this.features[f][1],this.drawGeometry(c,d,b.id),d.label&&a.push([b,d]));b=0;for(c=a.length;b<c;++b)f=
2258 a[b],this.drawText(f[0].geometry.getCentroid(),f[1])}},CLASS_NAME:"OpenLayers.Renderer.Canvas"});OpenLayers.Renderer.Canvas.LABEL_ALIGN={l:"left",r:"right",t:"top",b:"bottom"};OpenLayers.Renderer.Canvas.LABEL_FACTOR={l:0,r:-1,t:0,b:-1};OpenLayers.Renderer.Canvas.drawImageScaleFactor=null;OpenLayers.Format.OSM=OpenLayers.Class(OpenLayers.Format.XML,{checkTags:!1,interestingTagsExclude:null,areaTags:null,initialize:function(a){for(var b={interestingTagsExclude:"source source_ref source:ref history attribution created_by".split(" "),areaTags:"area building leisure tourism ruins historic landuse military natural sport".split(" ")},b=OpenLayers.Util.extend(b,a),c={},a=0;a<b.interestingTagsExclude.length;a++)c[b.interestingTagsExclude[a]]=!0;b.interestingTagsExclude=c;c={};for(a=0;a<b.areaTags.length;a++)c[b.areaTags[a]]=
2259 !0;b.areaTags=c;this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[b])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var b=this.getNodes(a),c=this.getWays(a),a=Array(c.length),d=0;d<c.length;d++){for(var e=Array(c[d].nodes.length),f=this.isWayArea(c[d])?1:0,g=0;g<c[d].nodes.length;g++){var h=b[c[d].nodes[g]],i=new OpenLayers.Geometry.Point(h.lon,h.lat);i.osm_id=parseInt(c[d].nodes[g]);
2260 e[g]=i;h.used=!0}h=null;h=f?new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(e)):new OpenLayers.Geometry.LineString(e);this.internalProjection&&this.externalProjection&&h.transform(this.externalProjection,this.internalProjection);e=new OpenLayers.Feature.Vector(h,c[d].tags);e.osm_id=parseInt(c[d].id);e.fid="way."+e.osm_id;a[d]=e}for(var j in b){h=b[j];if(!h.used||this.checkTags){c=null;if(this.checkTags){c=this.getTags(h.node,!0);if(h.used&&!c[1])continue;c=c[0]}else c=this.getTags(h.node);
2261 e=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(h.lon,h.lat),c);this.internalProjection&&this.externalProjection&&e.geometry.transform(this.externalProjection,this.internalProjection);e.osm_id=parseInt(j);e.fid="node."+e.osm_id;a.push(e)}h.node=null}return a},getNodes:function(a){for(var a=a.getElementsByTagName("node"),b={},c=0;c<a.length;c++){var d=a[c],e=d.getAttribute("id");b[e]={lat:d.getAttribute("lat"),lon:d.getAttribute("lon"),node:d}}return b},getWays:function(a){for(var a=
2262 a.getElementsByTagName("way"),b=[],c=0;c<a.length;c++){var d=a[c],e={id:d.getAttribute("id")};e.tags=this.getTags(d);d=d.getElementsByTagName("nd");e.nodes=Array(d.length);for(var f=0;f<d.length;f++)e.nodes[f]=d[f].getAttribute("ref");b.push(e)}return b},getTags:function(a,b){for(var c=a.getElementsByTagName("tag"),d={},e=!1,f=0;f<c.length;f++){var g=c[f].getAttribute("k");d[g]=c[f].getAttribute("v");b&&(this.interestingTagsExclude[g]||(e=!0))}return b?[d,e]:d},isWayArea:function(a){var b=!1,c=!1;
2263 a.nodes[0]==a.nodes[a.nodes.length-1]&&(b=!0);if(this.checkTags)for(var d in a.tags)if(this.areaTags[d]){c=!0;break}return b&&(this.checkTags?c:!0)},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);this.osm_id=1;this.created_nodes={};var b=this.createElementNS(null,"osm");b.setAttribute("version","0.5");b.setAttribute("generator","OpenLayers "+OpenLayers.VERSION_NUMBER);for(var c=a.length-1;0<=c;c--)for(var d=this.createFeatureNodes(a[c]),e=0;e<d.length;e++)b.appendChild(d[e]);return OpenLayers.Format.XML.prototype.write.apply(this,
2264 [b])},createFeatureNodes:function(a){var b=[],c=a.geometry.CLASS_NAME,c=c.substring(c.lastIndexOf(".")+1),c=c.toLowerCase();(c=this.createXML[c])&&(b=c.apply(this,[a]));return b},createXML:{point:function(a){var b=null,c=a.geometry?a.geometry:a;this.internalProjection&&this.externalProjection&&(c=c.clone(),c.transform(this.internalProjection,this.externalProjection));var d=!1;a.osm_id?(b=a.osm_id,this.created_nodes[b]&&(d=!0)):(b=-this.osm_id,this.osm_id++);var e=d?this.created_nodes[b]:this.createElementNS(null,
2265 "node");this.created_nodes[b]=e;e.setAttribute("id",b);e.setAttribute("lon",c.x);e.setAttribute("lat",c.y);a.attributes&&this.serializeTags(a,e);this.setState(a,e);return d?[]:[e]},linestring:function(a){var b,c=[],d=a.geometry;a.osm_id?b=a.osm_id:(b=-this.osm_id,this.osm_id++);var e=this.createElementNS(null,"way");e.setAttribute("id",b);for(b=0;b<d.components.length;b++){var f=this.createXML.point.apply(this,[d.components[b]]);if(f.length){var f=f[0],g=f.getAttribute("id");c.push(f)}else g=d.components[b].osm_id,
2266 f=this.created_nodes[g];this.setState(a,f);f=this.createElementNS(null,"nd");f.setAttribute("ref",g);e.appendChild(f)}this.serializeTags(a,e);c.push(e);return c},polygon:function(a){var b=OpenLayers.Util.extend({area:"yes"},a.attributes),b=new OpenLayers.Feature.Vector(a.geometry.components[0],b);b.osm_id=a.osm_id;return this.createXML.linestring.apply(this,[b])}},serializeTags:function(a,b){for(var c in a.attributes){var d=this.createElementNS(null,"tag");d.setAttribute("k",c);d.setAttribute("v",
2267 a.attributes[c]);b.appendChild(d)}},setState:function(a,b){if(a.state){var c=null;switch(a.state){case OpenLayers.State.UPDATE:case OpenLayers.State.DELETE:c="delete"}c&&b.setAttribute("action",c)}},CLASS_NAME:"OpenLayers.Format.OSM"});OpenLayers.Handler=OpenLayers.Class({id:null,control:null,map:null,keyMask:null,active:!1,evt:null,initialize:function(a,b,c){OpenLayers.Util.extend(this,c);this.control=a;this.callbacks=b;(a=this.map||a.map)&&this.setMap(a);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},setMap:function(a){this.map=a},checkModifiers:function(a){return null==this.keyMask?!0:((a.shiftKey?OpenLayers.Handler.MOD_SHIFT:0)|(a.ctrlKey?OpenLayers.Handler.MOD_CTRL:0)|(a.altKey?OpenLayers.Handler.MOD_ALT:0))==
2268 this.keyMask},activate:function(){if(this.active)return!1;for(var a=OpenLayers.Events.prototype.BROWSER_EVENTS,b=0,c=a.length;b<c;b++)this[a[b]]&&this.register(a[b],this[a[b]]);return this.active=!0},deactivate:function(){if(!this.active)return!1;for(var a=OpenLayers.Events.prototype.BROWSER_EVENTS,b=0,c=a.length;b<c;b++)this[a[b]]&&this.unregister(a[b],this[a[b]]);this.active=!1;return!0},callback:function(a,b){a&&this.callbacks[a]&&this.callbacks[a].apply(this.control,b)},register:function(a,b){this.map.events.registerPriority(a,
2269 this,b);this.map.events.registerPriority(a,this,this.setEvent)},unregister:function(a,b){this.map.events.unregister(a,this,b);this.map.events.unregister(a,this,this.setEvent)},setEvent:function(a){this.evt=a;return!0},destroy:function(){this.deactivate();this.control=this.map=null},CLASS_NAME:"OpenLayers.Handler"});OpenLayers.Handler.MOD_NONE=0;OpenLayers.Handler.MOD_SHIFT=1;OpenLayers.Handler.MOD_CTRL=2;OpenLayers.Handler.MOD_ALT=4;OpenLayers.Handler.Drag=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!0,dragging:!1,touch:!1,last:null,start:null,lastMoveEvt:null,oldOnselectstart:null,interval:0,timeoutId:null,documentDrag:!1,documentEvents:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);if(!0===this.documentDrag){var d=this;this._docMove=function(a){d.mousemove({xy:{x:a.clientX,y:a.clientY},element:document})};this._docUp=function(a){d.mouseup({xy:{x:a.clientX,y:a.clientY}})}}},
2270 dragstart:function(a){var b=!0;this.dragging=!1;this.checkModifiers(a)&&(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))?(this.started=!0,this.last=this.start=a.xy,OpenLayers.Element.addClass(this.map.viewPortDiv,"olDragDown"),this.down(a),this.callback("down",[a.xy]),OpenLayers.Event.stop(a),this.oldOnselectstart||(this.oldOnselectstart=document.onselectstart?document.onselectstart:OpenLayers.Function.True),document.onselectstart=OpenLayers.Function.False,b=!this.stopDown):(this.started=
2271 !1,this.last=this.start=null);return b},dragmove:function(a){this.lastMoveEvt=a;if(this.started&&!this.timeoutId&&(a.xy.x!=this.last.x||a.xy.y!=this.last.y))!0===this.documentDrag&&this.documentEvents&&(a.element===document?(this.adjustXY(a),this.setEvent(a)):this.removeDocumentEvents()),0<this.interval&&(this.timeoutId=setTimeout(OpenLayers.Function.bind(this.removeTimeout,this),this.interval)),this.dragging=!0,this.move(a),this.callback("move",[a.xy]),this.oldOnselectstart||(this.oldOnselectstart=
2272 document.onselectstart,document.onselectstart=OpenLayers.Function.False),this.last=a.xy;return!0},dragend:function(a){if(this.started){!0===this.documentDrag&&this.documentEvents&&(this.adjustXY(a),this.removeDocumentEvents());var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.up(a);this.callback("up",[a.xy]);b&&this.callback("done",[a.xy]);document.onselectstart=this.oldOnselectstart}return!0},down:function(){},move:function(){},
2273 up:function(){},out:function(){},mousedown:function(a){return this.dragstart(a)},touchstart:function(a){this.touch||(this.touch=!0,this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,scope:this}));return this.dragstart(a)},mousemove:function(a){return this.dragmove(a)},touchmove:function(a){return this.dragmove(a)},removeTimeout:function(){this.timeoutId=null;this.dragging&&this.mousemove(this.lastMoveEvt)},mouseup:function(a){return this.dragend(a)},
2274 touchend:function(a){a.xy=this.last;return this.dragend(a)},mouseout:function(a){if(this.started&&OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv))if(!0===this.documentDrag)this.addDocumentEvents();else{var b=this.start!=this.last;this.dragging=this.started=!1;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown");this.out(a);this.callback("out",[]);b&&this.callback("done",[a.xy]);document.onselectstart&&(document.onselectstart=this.oldOnselectstart)}return!0},click:function(){return this.start==
2275 this.last},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.dragging=!1,a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.dragging=this.started=this.touch=!1,this.last=this.start=null,a=!0,OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDragDown"));return a},adjustXY:function(a){var b=OpenLayers.Util.pagePosition(this.map.viewPortDiv);a.xy.x-=b[0];a.xy.y-=b[1]},addDocumentEvents:function(){OpenLayers.Element.addClass(document.body,
2276 "olDragDown");this.documentEvents=!0;OpenLayers.Event.observe(document,"mousemove",this._docMove);OpenLayers.Event.observe(document,"mouseup",this._docUp)},removeDocumentEvents:function(){OpenLayers.Element.removeClass(document.body,"olDragDown");this.documentEvents=!1;OpenLayers.Event.stopObserving(document,"mousemove",this._docMove);OpenLayers.Event.stopObserving(document,"mouseup",this._docUp)},CLASS_NAME:"OpenLayers.Handler.Drag"});OpenLayers.Handler.Feature=OpenLayers.Class(OpenLayers.Handler,{EVENTMAP:{click:{"in":"click",out:"clickout"},mousemove:{"in":"over",out:"out"},dblclick:{"in":"dblclick",out:null},mousedown:{"in":null,out:null},mouseup:{"in":null,out:null},touchstart:{"in":"click",out:"clickout"}},feature:null,lastFeature:null,down:null,up:null,touch:!1,clickTolerance:4,geometryTypes:null,stopClick:!0,stopDown:!0,stopUp:!1,initialize:function(a,b,c,d){OpenLayers.Handler.prototype.initialize.apply(this,[a,c,d]);this.layer=
2277 b},touchstart:function(a){this.touch||(this.touch=!0,this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,scope:this}));return OpenLayers.Event.isMultiTouch(a)?!0:this.mousedown(a)},touchmove:function(a){OpenLayers.Event.stop(a)},mousedown:function(a){if(OpenLayers.Event.isLeftClick(a)||OpenLayers.Event.isSingleTouch(a))this.down=a.xy;return this.handle(a)?!this.stopDown:!0},mouseup:function(a){this.up=a.xy;return this.handle(a)?
2278 !this.stopUp:!0},click:function(a){return this.handle(a)?!this.stopClick:!0},mousemove:function(a){if(!this.callbacks.over&&!this.callbacks.out)return!0;this.handle(a);return!0},dblclick:function(a){return!this.handle(a)},geometryTypeMatches:function(a){return null==this.geometryTypes||-1<OpenLayers.Util.indexOf(this.geometryTypes,a.geometry.CLASS_NAME)},handle:function(a){this.feature&&!this.feature.layer&&(this.feature=null);var b=a.type,c=!1,d=!!this.feature,e="click"==b||"dblclick"==b||"touchstart"==
2279 b;if((this.feature=this.layer.getFeatureFromEvent(a))&&!this.feature.layer)this.feature=null;this.lastFeature&&!this.lastFeature.layer&&(this.lastFeature=null);this.feature?("touchstart"===b&&OpenLayers.Event.stop(a),a=this.feature!=this.lastFeature,this.geometryTypeMatches(this.feature)?(d&&a?(this.lastFeature&&this.triggerCallback(b,"out",[this.lastFeature]),this.triggerCallback(b,"in",[this.feature])):(!d||e)&&this.triggerCallback(b,"in",[this.feature]),this.lastFeature=this.feature,c=!0):(this.lastFeature&&
2280 (d&&a||e)&&this.triggerCallback(b,"out",[this.lastFeature]),this.feature=null)):this.lastFeature&&(d||e)&&this.triggerCallback(b,"out",[this.lastFeature]);return c},triggerCallback:function(a,b,c){(b=this.EVENTMAP[a][b])&&("click"==a&&this.up&&this.down?Math.sqrt(Math.pow(this.up.x-this.down.x,2)+Math.pow(this.up.y-this.down.y,2))<=this.clickTolerance&&this.callback(b,c):this.callback(b,c))},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.moveLayerToTop(),
2281 this.map.events.on({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.moveLayerBack(),this.up=this.down=this.lastFeature=this.feature=null,this.touch=!1,this.map.events.un({removelayer:this.handleMapEvents,changelayer:this.handleMapEvents,scope:this}),a=!0);return a},handleMapEvents:function(a){("removelayer"==a.type||"order"==a.property)&&this.moveLayerToTop()},
2282 moveLayerToTop:function(){this.layer.setZIndex(Math.max(this.map.Z_INDEX_BASE.Feature-1,this.layer.getZIndex())+1)},moveLayerBack:function(){var a=this.layer.getZIndex()-1;a>=this.map.Z_INDEX_BASE.Feature?this.layer.setZIndex(a):this.map.setLayerZIndex(this.layer,this.map.getLayerIndex(this.layer))},CLASS_NAME:"OpenLayers.Handler.Feature"});OpenLayers.Control.DragFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,onStart:function(){},onDrag:function(){},onComplete:function(){},onEnter:function(){},onLeave:function(){},documentDrag:!1,layer:null,feature:null,dragCallbacks:{},featureCallbacks:{},lastPixel:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.handlers={drag:new OpenLayers.Handler.Drag(this,OpenLayers.Util.extend({down:this.downFeature,move:this.moveFeature,
2283 up:this.upFeature,out:this.cancel,done:this.doneDragging},this.dragCallbacks),{documentDrag:this.documentDrag}),feature:new OpenLayers.Handler.Feature(this,this.layer,OpenLayers.Util.extend({click:this.clickFeature,clickout:this.clickoutFeature,over:this.overFeature,out:this.outFeature},this.featureCallbacks),{geometryTypes:this.geometryTypes})}},clickFeature:function(a){this.handlers.feature.touch&&(!this.over&&this.overFeature(a))&&(this.handlers.drag.dragstart(this.handlers.feature.evt),this.handlers.drag.stopDown=
2284 !1)},clickoutFeature:function(a){this.handlers.feature.touch&&this.over&&(this.outFeature(a),this.handlers.drag.stopDown=!0)},destroy:function(){this.layer=null;OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){return this.handlers.feature.activate()&&OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.handlers.drag.deactivate();this.handlers.feature.deactivate();this.feature=null;this.dragging=!1;this.lastPixel=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,
2285 this.displayClass+"Over");return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},overFeature:function(a){var b=!1;this.handlers.drag.dragging?this.over=this.feature.id==a.id?!0:!1:(this.feature=a,this.handlers.drag.activate(),this.over=b=!0,OpenLayers.Element.addClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onEnter(a));return b},downFeature:function(a){this.lastPixel=a;this.onStart(this.feature,a)},moveFeature:function(a){var b=this.map.getResolution();this.feature.geometry.move(b*
2286 (a.x-this.lastPixel.x),b*(this.lastPixel.y-a.y));this.layer.drawFeature(this.feature);this.lastPixel=a;this.onDrag(this.feature,a)},upFeature:function(){this.over||this.handlers.drag.deactivate()},doneDragging:function(a){this.onComplete(this.feature,a)},outFeature:function(a){this.handlers.drag.dragging?this.feature.id==a.id&&(this.over=!1):(this.over=!1,this.handlers.drag.deactivate(),OpenLayers.Element.removeClass(this.map.viewPortDiv,this.displayClass+"Over"),this.onLeave(a),this.feature=null)},
2287 cancel:function(){this.handlers.drag.deactivate();this.over=!1},setMap:function(a){this.handlers.drag.setMap(a);this.handlers.feature.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.DragFeature"});OpenLayers.StyleMap=OpenLayers.Class({styles:null,extendDefault:!0,initialize:function(a,b){this.styles={"default":new OpenLayers.Style(OpenLayers.Feature.Vector.style["default"]),select:new OpenLayers.Style(OpenLayers.Feature.Vector.style.select),temporary:new OpenLayers.Style(OpenLayers.Feature.Vector.style.temporary),"delete":new OpenLayers.Style(OpenLayers.Feature.Vector.style["delete"])};if(a instanceof OpenLayers.Style)this.styles["default"]=a,this.styles.select=a,this.styles.temporary=a,this.styles["delete"]=
2288 a;else if("object"==typeof a)for(var c in a)if(a[c]instanceof OpenLayers.Style)this.styles[c]=a[c];else if("object"==typeof a[c])this.styles[c]=new OpenLayers.Style(a[c]);else{this.styles["default"]=new OpenLayers.Style(a);this.styles.select=new OpenLayers.Style(a);this.styles.temporary=new OpenLayers.Style(a);this.styles["delete"]=new OpenLayers.Style(a);break}OpenLayers.Util.extend(this,b)},destroy:function(){for(var a in this.styles)this.styles[a].destroy();this.styles=null},createSymbolizer:function(a,
2289 b){a||(a=new OpenLayers.Feature.Vector);this.styles[b]||(b="default");a.renderIntent=b;var c={};this.extendDefault&&"default"!=b&&(c=this.styles["default"].createSymbolizer(a));return OpenLayers.Util.extend(c,this.styles[b].createSymbolizer(a))},addUniqueValueRules:function(a,b,c,d){var e=[],f;for(f in c)e.push(new OpenLayers.Rule({symbolizer:c[f],context:d,filter:new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO,property:b,value:f})}));this.styles[a].addRules(e)},CLASS_NAME:"OpenLayers.StyleMap"});OpenLayers.Layer.Vector=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,isFixed:!1,features:null,filter:null,selectedFeatures:null,unrenderedFeatures:null,reportError:!0,style:null,styleMap:null,strategies:null,protocol:null,renderers:["SVG","VML","Canvas"],renderer:null,rendererOptions:null,geometryType:null,drawn:!1,ratio:1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);(!this.renderer||!this.renderer.supported())&&this.assignRenderer();if(!this.renderer||
2290 !this.renderer.supported())this.renderer=null,this.displayError();this.styleMap||(this.styleMap=new OpenLayers.StyleMap);this.features=[];this.selectedFeatures=[];this.unrenderedFeatures={};if(this.strategies)for(var c=0,d=this.strategies.length;c<d;c++)this.strategies[c].setLayer(this)},destroy:function(){if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoDestroy&&a.destroy();this.strategies=null}this.protocol&&(this.protocol.autoDestroy&&this.protocol.destroy(),
2291 this.protocol=null);this.destroyFeatures();this.unrenderedFeatures=this.selectedFeatures=this.features=null;this.renderer&&this.renderer.destroy();this.drawn=this.geometryType=this.renderer=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Vector(this.name,this.getOptions()));for(var a=OpenLayers.Layer.prototype.clone.apply(this,[a]),b=this.features,c=b.length,d=Array(c),e=0;e<c;++e)d[e]=b[e].clone();a.features=d;return a},refresh:function(a){this.calculateInRange()&&
2292 this.visibility&&this.events.triggerEvent("refresh",a)},assignRenderer:function(){for(var a=0,b=this.renderers.length;a<b;a++){var c=this.renderers[a];if((c="function"==typeof c?c:OpenLayers.Renderer[c])&&c.prototype.supported()){this.renderer=new c(this.div,this.rendererOptions);break}}},displayError:function(){this.reportError&&OpenLayers.Console.userError(OpenLayers.i18n("browserNotSupported",{renderers:this.renderers.join("\n")}))},setMap:function(a){OpenLayers.Layer.prototype.setMap.apply(this,
2293 arguments);if(this.renderer){this.renderer.map=this.map;var b=this.map.getSize();b.w*=this.ratio;b.h*=this.ratio;this.renderer.setSize(b)}else this.map.removeLayer(this)},afterAdd:function(){if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoActivate&&a.activate()}},removeMap:function(){this.drawn=!1;if(this.strategies){var a,b,c;b=0;for(c=this.strategies.length;b<c;b++)a=this.strategies[b],a.autoActivate&&a.deactivate()}},onMapResize:function(){OpenLayers.Layer.prototype.onMapResize.apply(this,
2294 arguments);var a=this.map.getSize();a.w*=this.ratio;a.h*=this.ratio;this.renderer.setSize(a)},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,arguments);var d=!0;if(!c){this.renderer.root.style.visibility="hidden";var d=this.map.getSize(),e=d.w,d=d.h,e=e/2*this.ratio-e/2,d=d/2*this.ratio-d/2,e=e+parseInt(this.map.layerContainerDiv.style.left,10),e=-Math.round(e),d=d+parseInt(this.map.layerContainerDiv.style.top,10),d=-Math.round(d);this.div.style.left=e+"px";this.div.style.top=
2295 d+"px";d=this.renderer.setExtent(this.map.getExtent().scale(this.ratio),b);this.renderer.root.style.visibility="visible";!0===OpenLayers.IS_GECKO&&(this.div.scrollLeft=this.div.scrollLeft);if(!b&&d)for(var f in this.unrenderedFeatures)e=this.unrenderedFeatures[f],this.drawFeature(e)}if(!this.drawn||b||!d){this.drawn=!0;f=0;for(d=this.features.length;f<d;f++)this.renderer.locked=f!==d-1,e=this.features[f],this.drawFeature(e)}},display:function(a){OpenLayers.Layer.prototype.display.apply(this,arguments);
2296 var b=this.div.style.display;b!=this.renderer.root.style.display&&(this.renderer.root.style.display=b)},addFeatures:function(a,b){OpenLayers.Util.isArray(a)||(a=[a]);var c=!b||!b.silent;if(c){var d={features:a};if(!1===this.events.triggerEvent("beforefeaturesadded",d))return;a=d.features}for(var d=[],e=0,f=a.length;e<f;e++){this.renderer.locked=e!=a.length-1?!0:!1;var g=a[e];if(this.geometryType&&!(g.geometry instanceof this.geometryType))throw new TypeError("addFeatures: component should be an "+
2297 this.geometryType.prototype.CLASS_NAME);g.layer=this;!g.style&&this.style&&(g.style=OpenLayers.Util.extend({},this.style));if(c){if(!1===this.events.triggerEvent("beforefeatureadded",{feature:g}))continue;this.preFeatureInsert(g)}d.push(g);this.features.push(g);this.drawFeature(g);c&&(this.events.triggerEvent("featureadded",{feature:g}),this.onFeatureInsert(g))}c&&this.events.triggerEvent("featuresadded",{features:d})},removeFeatures:function(a,b){if(a&&0!==a.length){if(a===this.features)return this.removeAllFeatures(b);
2298 OpenLayers.Util.isArray(a)||(a=[a]);a===this.selectedFeatures&&(a=a.slice());var c=!b||!b.silent;c&&this.events.triggerEvent("beforefeaturesremoved",{features:a});for(var d=a.length-1;0<=d;d--){this.renderer.locked=0!=d&&a[d-1].geometry?!0:!1;var e=a[d];delete this.unrenderedFeatures[e.id];c&&this.events.triggerEvent("beforefeatureremoved",{feature:e});this.features=OpenLayers.Util.removeItem(this.features,e);e.layer=null;e.geometry&&this.renderer.eraseFeatures(e);-1!=OpenLayers.Util.indexOf(this.selectedFeatures,
2299 e)&&OpenLayers.Util.removeItem(this.selectedFeatures,e);c&&this.events.triggerEvent("featureremoved",{feature:e})}c&&this.events.triggerEvent("featuresremoved",{features:a})}},removeAllFeatures:function(a){var a=!a||!a.silent,b=this.features;a&&this.events.triggerEvent("beforefeaturesremoved",{features:b});for(var c,d=b.length-1;0<=d;d--)c=b[d],a&&this.events.triggerEvent("beforefeatureremoved",{feature:c}),c.layer=null,a&&this.events.triggerEvent("featureremoved",{feature:c});this.renderer.clear();
2300 this.features=[];this.unrenderedFeatures={};this.selectedFeatures=[];a&&this.events.triggerEvent("featuresremoved",{features:b})},destroyFeatures:function(a,b){void 0==a&&(a=this.features);if(a){this.removeFeatures(a,b);for(var c=a.length-1;0<=c;c--)a[c].destroy()}},drawFeature:function(a,b){if(this.drawn){if("object"!=typeof b){!b&&a.state===OpenLayers.State.DELETE&&(b="delete");var c=b||a.renderIntent;(b=a.style||this.style)||(b=this.styleMap.createSymbolizer(a,c))}c=this.renderer.drawFeature(a,
2301 b);!1===c||null===c?this.unrenderedFeatures[a.id]=a:delete this.unrenderedFeatures[a.id]}},eraseFeatures:function(a){this.renderer.eraseFeatures(a)},getFeatureFromEvent:function(a){if(!this.renderer)throw Error("getFeatureFromEvent called on layer with no renderer. This usually means you destroyed a layer, but not some handler which is associated with it.");var b=null;(a=this.renderer.getFeatureIdFromEvent(a))&&(b="string"===typeof a?this.getFeatureById(a):a);return b},getFeatureBy:function(a,b){for(var c=
2302 null,d=0,e=this.features.length;d<e;++d)if(this.features[d][a]==b){c=this.features[d];break}return c},getFeatureById:function(a){return this.getFeatureBy("id",a)},getFeatureByFid:function(a){return this.getFeatureBy("fid",a)},getFeaturesByAttribute:function(a,b){var c,d,e=this.features.length,f=[];for(c=0;c<e;c++)(d=this.features[c])&&d.attributes&&d.attributes[a]===b&&f.push(d);return f},onFeatureInsert:function(){},preFeatureInsert:function(){},getDataExtent:function(){var a=null,b=this.features;
2303 if(b&&0<b.length)for(var c=null,d=0,e=b.length;d<e;d++)if(c=b[d].geometry)null===a&&(a=new OpenLayers.Bounds),a.extend(c.getBounds());return a},CLASS_NAME:"OpenLayers.Layer.Vector"});OpenLayers.Layer.Vector.RootContainer=OpenLayers.Class(OpenLayers.Layer.Vector,{displayInLayerSwitcher:!1,layers:null,display:function(){},getFeatureFromEvent:function(a){for(var b=this.layers,c,d=0;d<b.length;d++)if(c=b[d].getFeatureFromEvent(a))return c},setMap:function(a){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);this.collectRoots();a.events.register("changelayer",this,this.handleChangeLayer)},removeMap:function(a){a.events.unregister("changelayer",this,this.handleChangeLayer);
2304 this.resetRoots();OpenLayers.Layer.Vector.prototype.removeMap.apply(this,arguments)},collectRoots:function(){for(var a,b=0;b<this.map.layers.length;++b)a=this.map.layers[b],-1!=OpenLayers.Util.indexOf(this.layers,a)&&a.renderer.moveRoot(this.renderer)},resetRoots:function(){for(var a,b=0;b<this.layers.length;++b)a=this.layers[b],this.renderer&&a.renderer.getRenderLayerId()==this.id&&this.renderer.moveRoot(a.renderer)},handleChangeLayer:function(a){var b=a.layer;"order"==a.property&&-1!=OpenLayers.Util.indexOf(this.layers,
2305 b)&&(this.resetRoots(),this.collectRoots())},CLASS_NAME:"OpenLayers.Layer.Vector.RootContainer"});OpenLayers.Control.SelectFeature=OpenLayers.Class(OpenLayers.Control,{multipleKey:null,toggleKey:null,multiple:!1,clickout:!0,toggle:!1,hover:!1,highlightOnly:!1,box:!1,onBeforeSelect:function(){},onSelect:function(){},onUnselect:function(){},scope:null,geometryTypes:null,layer:null,layers:null,callbacks:null,selectStyle:null,renderIntent:"select",handlers:null,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);null===this.scope&&(this.scope=this);this.initLayer(a);var c=
2306 {click:this.clickFeature,clickout:this.clickoutFeature};this.hover&&(c.over=this.overFeature,c.out=this.outFeature);this.callbacks=OpenLayers.Util.extend(c,this.callbacks);this.handlers={feature:new OpenLayers.Handler.Feature(this,this.layer,this.callbacks,{geometryTypes:this.geometryTypes})};this.box&&(this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},{boxDivClassName:"olHandlerBoxSelectFeature"}))},initLayer:function(a){OpenLayers.Util.isArray(a)?(this.layers=a,this.layer=
2307 new OpenLayers.Layer.Vector.RootContainer(this.id+"_container",{layers:a})):this.layer=a},destroy:function(){this.active&&this.layers&&this.map.removeLayer(this.layer);OpenLayers.Control.prototype.destroy.apply(this,arguments);this.layers&&this.layer.destroy()},activate:function(){this.active||(this.layers&&this.map.addLayer(this.layer),this.handlers.feature.activate(),this.box&&this.handlers.box&&this.handlers.box.activate());return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.active&&
2308 (this.handlers.feature.deactivate(),this.handlers.box&&this.handlers.box.deactivate(),this.layers&&this.map.removeLayer(this.layer));return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},unselectAll:function(a){for(var b=this.layers||[this.layer],c,d,e=0;e<b.length;++e){c=b[e];for(var f=c.selectedFeatures.length-1;0<=f;--f)d=c.selectedFeatures[f],(!a||a.except!=d)&&this.unselect(d)}},clickFeature:function(a){this.hover||(-1<OpenLayers.Util.indexOf(a.layer.selectedFeatures,a)?this.toggleSelect()?
2309 this.unselect(a):this.multipleSelect()||this.unselectAll({except:a}):(this.multipleSelect()||this.unselectAll({except:a}),this.select(a)))},multipleSelect:function(){return this.multiple||this.handlers.feature.evt&&this.handlers.feature.evt[this.multipleKey]},toggleSelect:function(){return this.toggle||this.handlers.feature.evt&&this.handlers.feature.evt[this.toggleKey]},clickoutFeature:function(){!this.hover&&this.clickout&&this.unselectAll()},overFeature:function(a){var b=a.layer;this.hover&&(this.highlightOnly?
2310 this.highlight(a):-1==OpenLayers.Util.indexOf(b.selectedFeatures,a)&&this.select(a))},outFeature:function(a){if(this.hover)if(this.highlightOnly){if(a._lastHighlighter==this.id)if(a._prevHighlighter&&a._prevHighlighter!=this.id){delete a._lastHighlighter;var b=this.map.getControl(a._prevHighlighter);b&&b.highlight(a)}else this.unhighlight(a)}else this.unselect(a)},highlight:function(a){var b=a.layer;!1!==this.events.triggerEvent("beforefeaturehighlighted",{feature:a})&&(a._prevHighlighter=a._lastHighlighter,
2311 a._lastHighlighter=this.id,b.drawFeature(a,this.selectStyle||this.renderIntent),this.events.triggerEvent("featurehighlighted",{feature:a}))},unhighlight:function(a){var b=a.layer;void 0==a._prevHighlighter?delete a._lastHighlighter:(a._prevHighlighter!=this.id&&(a._lastHighlighter=a._prevHighlighter),delete a._prevHighlighter);b.drawFeature(a,a.style||a.layer.style||"default");this.events.triggerEvent("featureunhighlighted",{feature:a})},select:function(a){var b=this.onBeforeSelect.call(this.scope,
2312 a),c=a.layer;!1!==b&&(b=c.events.triggerEvent("beforefeatureselected",{feature:a}),!1!==b&&(c.selectedFeatures.push(a),this.highlight(a),this.handlers.feature.lastFeature||(this.handlers.feature.lastFeature=c.selectedFeatures[0]),c.events.triggerEvent("featureselected",{feature:a}),this.onSelect.call(this.scope,a)))},unselect:function(a){var b=a.layer;this.unhighlight(a);OpenLayers.Util.removeItem(b.selectedFeatures,a);b.events.triggerEvent("featureunselected",{feature:a});this.onUnselect.call(this.scope,
2313 a)},selectBox:function(a){if(a instanceof OpenLayers.Bounds){var b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),a=this.map.getLonLatFromPixel({x:a.right,y:a.top}),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);this.multipleSelect()||this.unselectAll();a=this.multiple;this.multiple=!0;var c=this.layers||[this.layer];this.events.triggerEvent("boxselectionstart",{layers:c});for(var d,e=0;e<c.length;++e){d=c[e];for(var f=0,g=d.features.length;f<g;++f){var h=d.features[f];h.getVisibility()&&(null==
2314 this.geometryTypes||-1<OpenLayers.Util.indexOf(this.geometryTypes,h.geometry.CLASS_NAME))&&b.toGeometry().intersects(h.geometry)&&-1==OpenLayers.Util.indexOf(d.selectedFeatures,h)&&this.select(h)}}this.multiple=a;this.events.triggerEvent("boxselectionend",{layers:c})}},setMap:function(a){this.handlers.feature.setMap(a);this.box&&this.handlers.box.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setLayer:function(a){var b=this.active;this.unselectAll();this.deactivate();this.layers&&
2315 (this.layer.destroy(),this.layers=null);this.initLayer(a);this.handlers.feature.layer=this.layer;b&&this.activate()},CLASS_NAME:"OpenLayers.Control.SelectFeature"});OpenLayers.Handler.Keyboard=OpenLayers.Class(OpenLayers.Handler,{KEY_EVENTS:["keydown","keyup"],eventListener:null,observeElement:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.eventListener=OpenLayers.Function.bindAsEventListener(this.handleKeyEvent,this)},destroy:function(){this.deactivate();this.eventListener=null;OpenLayers.Handler.prototype.destroy.apply(this,arguments)},activate:function(){if(OpenLayers.Handler.prototype.activate.apply(this,
2316 arguments)){this.observeElement=this.observeElement||document;for(var a=0,b=this.KEY_EVENTS.length;a<b;a++)OpenLayers.Event.observe(this.observeElement,this.KEY_EVENTS[a],this.eventListener);return!0}return!1},deactivate:function(){var a=!1;if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){for(var a=0,b=this.KEY_EVENTS.length;a<b;a++)OpenLayers.Event.stopObserving(this.observeElement,this.KEY_EVENTS[a],this.eventListener);a=!0}return a},handleKeyEvent:function(a){this.checkModifiers(a)&&
2317 this.callback(a.type,[a])},CLASS_NAME:"OpenLayers.Handler.Keyboard"});OpenLayers.Control.ModifyFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,clickout:!0,toggle:!0,standalone:!1,layer:null,feature:null,vertices:null,virtualVertices:null,selectControl:null,dragControl:null,handlers:null,deleteCodes:null,virtualStyle:null,vertexRenderIntent:null,mode:null,createVertices:!0,modified:!1,radiusHandle:null,dragHandle:null,onModificationStart:function(){},onModification:function(){},onModificationEnd:function(){},initialize:function(a,b){b=b||{};this.layer=
2318 a;this.vertices=[];this.virtualVertices=[];this.virtualStyle=OpenLayers.Util.extend({},this.layer.style||this.layer.styleMap.createSymbolizer(null,b.vertexRenderIntent));this.virtualStyle.fillOpacity=0.3;this.virtualStyle.strokeOpacity=0.3;this.deleteCodes=[46,68];this.mode=OpenLayers.Control.ModifyFeature.RESHAPE;OpenLayers.Control.prototype.initialize.apply(this,[b]);OpenLayers.Util.isArray(this.deleteCodes)||(this.deleteCodes=[this.deleteCodes]);var c=this,d={geometryTypes:this.geometryTypes,clickout:this.clickout,
2319 toggle:this.toggle,onBeforeSelect:this.beforeSelectFeature,onSelect:this.selectFeature,onUnselect:this.unselectFeature,scope:this};!1===this.standalone&&(this.selectControl=new OpenLayers.Control.SelectFeature(a,d));this.dragControl=new OpenLayers.Control.DragFeature(a,{geometryTypes:["OpenLayers.Geometry.Point"],onStart:function(a,b){c.dragStart.apply(c,[a,b])},onDrag:function(a,b){c.dragVertex.apply(c,[a,b])},onComplete:function(a){c.dragComplete.apply(c,[a])},featureCallbacks:{over:function(a){(c.standalone!==
2320 true||a._sketch||c.feature===a)&&c.dragControl.overFeature.apply(c.dragControl,[a])}}});this.handlers={keyboard:new OpenLayers.Handler.Keyboard(this,{keydown:this.handleKeypress})}},destroy:function(){this.layer=null;this.standalone||this.selectControl.destroy();this.dragControl.destroy();OpenLayers.Control.prototype.destroy.apply(this,[])},activate:function(){return(this.standalone||this.selectControl.activate())&&this.handlers.keyboard.activate()&&OpenLayers.Control.prototype.activate.apply(this,
2321 arguments)},deactivate:function(){var a=!1;if(OpenLayers.Control.prototype.deactivate.apply(this,arguments)){this.layer.removeFeatures(this.vertices,{silent:!0});this.layer.removeFeatures(this.virtualVertices,{silent:!0});this.vertices=[];this.dragControl.deactivate();var b=(a=this.feature)&&a.geometry&&a.layer;!1===this.standalone?(b&&this.selectControl.unselect.apply(this.selectControl,[a]),this.selectControl.deactivate()):b&&this.unselectFeature(a);this.handlers.keyboard.deactivate();a=!0}return a},
2322 beforeSelectFeature:function(a){return this.layer.events.triggerEvent("beforefeaturemodified",{feature:a})},selectFeature:function(a){if(!this.standalone||!1!==this.beforeSelectFeature(a))this.feature=a,this.modified=!1,this.resetVertices(),this.dragControl.activate(),this.onModificationStart(this.feature);var b=a.modified;if(a.geometry&&(!b||!b.geometry))this._originalGeometry=a.geometry.clone()},unselectFeature:function(a){this.layer.removeFeatures(this.vertices,{silent:!0});this.vertices=[];this.layer.destroyFeatures(this.virtualVertices,
2323 {silent:!0});this.virtualVertices=[];this.dragHandle&&(this.layer.destroyFeatures([this.dragHandle],{silent:!0}),delete this.dragHandle);this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),delete this.radiusHandle);this.feature=null;this.dragControl.deactivate();this.onModificationEnd(a);this.layer.events.triggerEvent("afterfeaturemodified",{feature:a,modified:this.modified});this.modified=!1},dragStart:function(a,b){if(a!=this.feature&&(!a.geometry.parent&&a!=this.dragHandle&&
2324 a!=this.radiusHandle)&&(!1===this.standalone&&this.feature&&this.selectControl.clickFeature.apply(this.selectControl,[this.feature]),null==this.geometryTypes||-1!=OpenLayers.Util.indexOf(this.geometryTypes,a.geometry.CLASS_NAME)))this.standalone||this.selectControl.clickFeature.apply(this.selectControl,[a]),this.dragControl.overFeature.apply(this.dragControl,[a]),this.dragControl.lastPixel=b,this.dragControl.handlers.drag.started=!0,this.dragControl.handlers.drag.start=b,this.dragControl.handlers.drag.last=
2325 b},dragVertex:function(a,b){this.modified=!0;"OpenLayers.Geometry.Point"==this.feature.geometry.CLASS_NAME?(this.feature!=a&&(this.feature=a),this.layer.events.triggerEvent("vertexmodified",{vertex:a.geometry,feature:this.feature,pixel:b})):(a._index?(a.geometry.parent.addComponent(a.geometry,a._index),delete a._index,OpenLayers.Util.removeItem(this.virtualVertices,a),this.vertices.push(a)):a==this.dragHandle?(this.layer.removeFeatures(this.vertices,{silent:!0}),this.vertices=[],this.radiusHandle&&
2326 (this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),this.radiusHandle=null)):a!==this.radiusHandle&&this.layer.events.triggerEvent("vertexmodified",{vertex:a.geometry,feature:this.feature,pixel:b}),0<this.virtualVertices.length&&(this.layer.destroyFeatures(this.virtualVertices,{silent:!0}),this.virtualVertices=[]),this.layer.drawFeature(this.feature,this.standalone?void 0:this.selectControl.renderIntent));this.layer.drawFeature(a)},dragComplete:function(){this.resetVertices();this.setFeatureState();
2327 this.onModification(this.feature);this.layer.events.triggerEvent("featuremodified",{feature:this.feature})},setFeatureState:function(){if(this.feature.state!=OpenLayers.State.INSERT&&this.feature.state!=OpenLayers.State.DELETE&&(this.feature.state=OpenLayers.State.UPDATE,this.modified&&this._originalGeometry)){var a=this.feature;a.modified=OpenLayers.Util.extend(a.modified,{geometry:this._originalGeometry});delete this._originalGeometry}},resetVertices:function(){this.dragControl.feature&&this.dragControl.outFeature(this.dragControl.feature);
2328 0<this.vertices.length&&(this.layer.removeFeatures(this.vertices,{silent:!0}),this.vertices=[]);0<this.virtualVertices.length&&(this.layer.removeFeatures(this.virtualVertices,{silent:!0}),this.virtualVertices=[]);this.dragHandle&&(this.layer.destroyFeatures([this.dragHandle],{silent:!0}),this.dragHandle=null);this.radiusHandle&&(this.layer.destroyFeatures([this.radiusHandle],{silent:!0}),this.radiusHandle=null);this.feature&&"OpenLayers.Geometry.Point"!=this.feature.geometry.CLASS_NAME&&(this.mode&
2329 OpenLayers.Control.ModifyFeature.DRAG&&this.collectDragHandle(),this.mode&(OpenLayers.Control.ModifyFeature.ROTATE|OpenLayers.Control.ModifyFeature.RESIZE)&&this.collectRadiusHandle(),this.mode&OpenLayers.Control.ModifyFeature.RESHAPE&&(this.mode&OpenLayers.Control.ModifyFeature.RESIZE||this.collectVertices()))},handleKeypress:function(a){var b=a.keyCode;if(this.feature&&-1!=OpenLayers.Util.indexOf(this.deleteCodes,b)&&(b=this.dragControl.feature)&&-1!=OpenLayers.Util.indexOf(this.vertices,b)&&!this.dragControl.handlers.drag.dragging&&
2330 b.geometry.parent)b.geometry.parent.removeComponent(b.geometry),this.layer.events.triggerEvent("vertexremoved",{vertex:b.geometry,feature:this.feature,pixel:a.xy}),this.layer.drawFeature(this.feature,this.standalone?void 0:this.selectControl.renderIntent),this.modified=!0,this.resetVertices(),this.setFeatureState(),this.onModification(this.feature),this.layer.events.triggerEvent("featuremodified",{feature:this.feature})},collectVertices:function(){function a(c){var d,e,f;if("OpenLayers.Geometry.Point"==
2331 c.CLASS_NAME)e=new OpenLayers.Feature.Vector(c),e._sketch=!0,e.renderIntent=b.vertexRenderIntent,b.vertices.push(e);else{f=c.components.length;"OpenLayers.Geometry.LinearRing"==c.CLASS_NAME&&(f-=1);for(d=0;d<f;++d)e=c.components[d],"OpenLayers.Geometry.Point"==e.CLASS_NAME?(e=new OpenLayers.Feature.Vector(e),e._sketch=!0,e.renderIntent=b.vertexRenderIntent,b.vertices.push(e)):a(e);if(b.createVertices&&"OpenLayers.Geometry.MultiPoint"!=c.CLASS_NAME){d=0;for(f=c.components.length;d<f-1;++d){e=c.components[d];
2332 var g=c.components[d+1];"OpenLayers.Geometry.Point"==e.CLASS_NAME&&"OpenLayers.Geometry.Point"==g.CLASS_NAME&&(e=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point((e.x+g.x)/2,(e.y+g.y)/2),null,b.virtualStyle),e.geometry.parent=c,e._index=d+1,e._sketch=!0,b.virtualVertices.push(e))}}}}this.vertices=[];this.virtualVertices=[];var b=this;a.call(this,this.feature.geometry);this.layer.addFeatures(this.virtualVertices,{silent:!0});this.layer.addFeatures(this.vertices,{silent:!0})},collectDragHandle:function(){var a=
2333 this.feature.geometry,b=a.getBounds().getCenterLonLat(),b=new OpenLayers.Geometry.Point(b.lon,b.lat),c=new OpenLayers.Feature.Vector(b);b.move=function(b,c){OpenLayers.Geometry.Point.prototype.move.call(this,b,c);a.move(b,c)};c._sketch=!0;this.dragHandle=c;this.dragHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.dragHandle],{silent:!0})},collectRadiusHandle:function(){var a=this.feature.geometry,b=a.getBounds(),c=b.getCenterLonLat(),d=new OpenLayers.Geometry.Point(c.lon,c.lat),
2334 b=new OpenLayers.Geometry.Point(b.right,b.bottom),c=new OpenLayers.Feature.Vector(b),e=this.mode&OpenLayers.Control.ModifyFeature.RESIZE,f=this.mode&OpenLayers.Control.ModifyFeature.RESHAPE,g=this.mode&OpenLayers.Control.ModifyFeature.ROTATE;b.move=function(b,c){OpenLayers.Geometry.Point.prototype.move.call(this,b,c);var j=this.x-d.x,k=this.y-d.y,l=j-b,m=k-c;if(g){var n=Math.atan2(m,l),n=Math.atan2(k,j)-n,n=n*(180/Math.PI);a.rotate(n,d)}if(e){var o;f?(k/=m,o=j/l/k):(l=Math.sqrt(l*l+m*m),k=Math.sqrt(j*
2335 j+k*k)/l);a.resize(k,d,o)}};c._sketch=!0;this.radiusHandle=c;this.radiusHandle.renderIntent=this.vertexRenderIntent;this.layer.addFeatures([this.radiusHandle],{silent:!0})},setMap:function(a){this.standalone||this.selectControl.setMap(a);this.dragControl.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.ModifyFeature"});OpenLayers.Control.ModifyFeature.RESHAPE=1;OpenLayers.Control.ModifyFeature.RESIZE=2;OpenLayers.Control.ModifyFeature.ROTATE=4;
2336 OpenLayers.Control.ModifyFeature.DRAG=8;OpenLayers.Layer.Bing=OpenLayers.Class(OpenLayers.Layer.XYZ,{key:null,serverResolutions:[156543.03390625,78271.516953125,39135.7584765625,19567.87923828125,9783.939619140625,4891.9698095703125,2445.9849047851562,1222.9924523925781,611.4962261962891,305.74811309814453,152.87405654907226,76.43702827453613,38.218514137268066,19.109257068634033,9.554628534317017,4.777314267158508,2.388657133579254,1.194328566789627,0.5971642833948135,0.29858214169740677,0.14929107084870338,0.07464553542435169],attributionTemplate:'<span class="olBingAttribution ${type}"><div><a target="_blank" href="http://www.bing.com/maps/"><img src="${logo}" /></a></div>${copyrights}<a style="white-space: nowrap" target="_blank" href="http://www.microsoft.com/maps/product/terms.html">Terms of Use</a></span>',
2337 metadata:null,type:"Road",culture:"en-US",metadataParams:null,tileOptions:null,initialize:function(a){a=OpenLayers.Util.applyDefaults({sphericalMercator:!0},a);OpenLayers.Layer.XYZ.prototype.initialize.apply(this,[a.name||"Bing "+(a.type||this.type),null,a]);this.tileOptions=OpenLayers.Util.extend({crossOriginKeyword:"anonymous"},this.options.tileOptions);this.loadMetadata()},loadMetadata:function(){this._callbackId="_callback_"+this.id.replace(/\./g,"_");window[this._callbackId]=OpenLayers.Function.bind(OpenLayers.Layer.Bing.processMetadata,
2338 this);var a=OpenLayers.Util.applyDefaults({key:this.key,jsonp:this._callbackId,include:"ImageryProviders"},this.metadataParams),a="http://dev.virtualearth.net/REST/v1/Imagery/Metadata/"+this.type+"?"+OpenLayers.Util.getParameterString(a),b=document.createElement("script");b.type="text/javascript";b.src=a;b.id=this._callbackId;document.getElementsByTagName("head")[0].appendChild(b)},initLayer:function(){var a=this.metadata.resourceSets[0].resources[0],b=a.imageUrl.replace("{quadkey}","${quadkey}"),
2339 b=b.replace("{culture}",this.culture);this.url=[];for(var c=0;c<a.imageUrlSubdomains.length;++c)this.url.push(b.replace("{subdomain}",a.imageUrlSubdomains[c]));this.addOptions({maxResolution:Math.min(this.serverResolutions[a.zoomMin],this.maxResolution||Number.POSITIVE_INFINITY),numZoomLevels:Math.min(a.zoomMax+1-a.zoomMin,this.numZoomLevels)},!0)},getURL:function(a){if(this.url){for(var b=this.getXYZ(a),a=b.x,c=b.y,b=b.z,d=[],e=b;0<e;--e){var f="0",g=1<<e-1;0!=(a&g)&&f++;0!=(c&g)&&(f++,f++);d.push(f)}d=
2340 d.join("");a=this.selectUrl(""+a+c+b,this.url);return OpenLayers.String.format(a,{quadkey:d})}},updateAttribution:function(){var a=this.metadata;if(a.resourceSets&&this.map&&this.map.center){var b=a.resourceSets[0].resources[0],c=this.map.getExtent().transform(this.map.getProjectionObject(),new OpenLayers.Projection("EPSG:4326")),b=b.imageryProviders,d=OpenLayers.Util.indexOf(this.serverResolutions,this.getServerResolution()),e="",f,g,h,i,j,k,l;g=0;for(h=b.length;g<h;++g){f=b[g];i=0;for(j=f.coverageAreas.length;i<
2341 j;++i)l=f.coverageAreas[i],k=OpenLayers.Bounds.fromArray(l.bbox,!0),c.intersectsBounds(k)&&(d<=l.zoomMax&&d>=l.zoomMin)&&(e+=f.attribution+" ")}this.attribution=OpenLayers.String.format(this.attributionTemplate,{type:this.type.toLowerCase(),logo:a.brandLogoUri,copyrights:e});this.map&&this.map.events.triggerEvent("changelayer",{layer:this,property:"attribution"})}},setMap:function(){OpenLayers.Layer.XYZ.prototype.setMap.apply(this,arguments);this.updateAttribution();this.map.events.register("moveend",
2342 this,this.updateAttribution)},clone:function(a){null==a&&(a=new OpenLayers.Layer.Bing(this.options));return a=OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},destroy:function(){this.map&&this.map.events.unregister("moveend",this,this.updateAttribution);OpenLayers.Layer.XYZ.prototype.destroy.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.Bing"});
2343 OpenLayers.Layer.Bing.processMetadata=function(a){this.metadata=a;this.initLayer();a=document.getElementById(this._callbackId);a.parentNode.removeChild(a);window[this._callbackId]=void 0;delete this._callbackId};OpenLayers.Layer.PointGrid=OpenLayers.Class(OpenLayers.Layer.Vector,{dx:null,dy:null,ratio:1.5,maxFeatures:250,rotation:0,origin:null,gridBounds:null,initialize:function(a){a=a||{};OpenLayers.Layer.Vector.prototype.initialize.apply(this,[a.name,a])},setMap:function(a){OpenLayers.Layer.Vector.prototype.setMap.apply(this,arguments);a.events.register("moveend",this,this.onMoveEnd)},removeMap:function(a){a.events.unregister("moveend",this,this.onMoveEnd);OpenLayers.Layer.Vector.prototype.removeMap.apply(this,
2344 arguments)},setRatio:function(a){this.ratio=a;this.updateGrid(!0)},setMaxFeatures:function(a){this.maxFeatures=a;this.updateGrid(!0)},setSpacing:function(a,b){this.dx=a;this.dy=b||a;this.updateGrid(!0)},setOrigin:function(a){this.origin=a;this.updateGrid(!0)},getOrigin:function(){this.origin||(this.origin=this.map.getExtent().getCenterLonLat());return this.origin},setRotation:function(a){this.rotation=a;this.updateGrid(!0)},onMoveEnd:function(){this.updateGrid()},getViewBounds:function(){var a=this.map.getExtent();
2345 if(this.rotation){var b=this.getOrigin(),b=new OpenLayers.Geometry.Point(b.lon,b.lat),a=a.toGeometry();a.rotate(-this.rotation,b);a=a.getBounds()}return a},updateGrid:function(a){if(a||this.invalidBounds()){var b=this.getViewBounds(),c=this.getOrigin(),a=new OpenLayers.Geometry.Point(c.lon,c.lat),d=b.getWidth(),e=b.getHeight(),f=d/e,g=Math.sqrt(this.dx*this.dy*this.maxFeatures/f),d=Math.min(d*this.ratio,g*f),e=Math.min(e*this.ratio,g),b=b.getCenterLonLat();this.gridBounds=new OpenLayers.Bounds(b.lon-
2346 d/2,b.lat-e/2,b.lon+d/2,b.lat+e/2);for(var b=Math.floor(e/this.dy),d=Math.floor(d/this.dx),e=c.lon+this.dx*Math.ceil((this.gridBounds.left-c.lon)/this.dx),c=c.lat+this.dy*Math.ceil((this.gridBounds.bottom-c.lat)/this.dy),g=Array(b*d),h,i=0;i<d;++i)for(var f=e+i*this.dx,j=0;j<b;++j)h=c+j*this.dy,h=new OpenLayers.Geometry.Point(f,h),this.rotation&&h.rotate(this.rotation,a),g[i*b+j]=new OpenLayers.Feature.Vector(h);this.destroyFeatures(this.features,{silent:!0});this.addFeatures(g,{silent:!0})}},invalidBounds:function(){return!this.gridBounds||
2347 !this.gridBounds.containsBounds(this.getViewBounds())},CLASS_NAME:"OpenLayers.Layer.PointGrid"});OpenLayers.Handler.MouseWheel=OpenLayers.Class(OpenLayers.Handler,{wheelListener:null,mousePosition:null,interval:0,delta:0,cumulative:!0,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.wheelListener=OpenLayers.Function.bindAsEventListener(this.onWheelEvent,this)},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.wheelListener=null},onWheelEvent:function(a){if(this.map&&this.checkModifiers(a)){for(var b=!1,c=!1,d=!1,e=
2348 OpenLayers.Event.element(a);null!=e&&!d&&!b;){if(!b)try{var f=e.currentStyle?e.currentStyle.overflow:document.defaultView.getComputedStyle(e,null).getPropertyValue("overflow"),b=f&&"auto"==f||"scroll"==f}catch(g){}if(!c)for(var d=0,h=this.map.layers.length;d<h;d++)if(e==this.map.layers[d].div||e==this.map.layers[d].pane){c=!0;break}d=e==this.map.div;e=e.parentNode}!b&&d&&(c&&((b=0,a||(a=window.event),a.wheelDelta?(b=a.wheelDelta/120,window.opera&&9.2>window.opera.version()&&(b=-b)):a.detail&&(b=-a.detail/
2349 3),this.delta+=b,this.interval)?(window.clearTimeout(this._timeoutId),this._timeoutId=window.setTimeout(OpenLayers.Function.bind(function(){this.wheelZoom(a)},this),this.interval)):this.wheelZoom(a)),OpenLayers.Event.stop(a))}},wheelZoom:function(a){var b=this.delta;this.delta=0;b&&(this.mousePosition&&(a.xy=this.mousePosition),a.xy||(a.xy=this.map.getPixelFromLonLat(this.map.getCenter())),0>b?this.callback("down",[a,this.cumulative?b:-1]):this.callback("up",[a,this.cumulative?b:1]))},mousemove:function(a){this.mousePosition=
2350 a.xy},activate:function(a){if(OpenLayers.Handler.prototype.activate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.observe(window,"DOMMouseScroll",b);OpenLayers.Event.observe(window,"mousewheel",b);OpenLayers.Event.observe(document,"mousewheel",b);return!0}return!1},deactivate:function(a){if(OpenLayers.Handler.prototype.deactivate.apply(this,arguments)){var b=this.wheelListener;OpenLayers.Event.stopObserving(window,"DOMMouseScroll",b);OpenLayers.Event.stopObserving(window,"mousewheel",
2351 b);OpenLayers.Event.stopObserving(document,"mousewheel",b);return!0}return!1},CLASS_NAME:"OpenLayers.Handler.MouseWheel"});OpenLayers.Symbolizer=OpenLayers.Class({zIndex:0,initialize:function(a){OpenLayers.Util.extend(this,a)},clone:function(){return new (eval(this.CLASS_NAME))(OpenLayers.Util.extend({},this))},CLASS_NAME:"OpenLayers.Symbolizer"});OpenLayers.Symbolizer.Raster=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Raster"});OpenLayers.Rule=OpenLayers.Class({id:null,name:null,title:null,description:null,context:null,filter:null,elseFilter:!1,symbolizer:null,symbolizers:null,minScaleDenominator:null,maxScaleDenominator:null,initialize:function(a){this.symbolizer={};OpenLayers.Util.extend(this,a);this.symbolizers&&delete this.symbolizer;this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a in this.symbolizer)this.symbolizer[a]=null;this.symbolizer=null;delete this.symbolizers},evaluate:function(a){var b=
2352 this.getContext(a),c=!0;if(this.minScaleDenominator||this.maxScaleDenominator)var d=a.layer.map.getScale();this.minScaleDenominator&&(c=d>=OpenLayers.Style.createLiteral(this.minScaleDenominator,b));c&&this.maxScaleDenominator&&(c=d<OpenLayers.Style.createLiteral(this.maxScaleDenominator,b));c&&this.filter&&(c="OpenLayers.Filter.FeatureId"==this.filter.CLASS_NAME?this.filter.evaluate(a):this.filter.evaluate(b));return c},getContext:function(a){var b=this.context;b||(b=a.attributes||a.data);"function"==
2353 typeof this.context&&(b=this.context(a));return b},clone:function(){var a=OpenLayers.Util.extend({},this);if(this.symbolizers){var b=this.symbolizers.length;a.symbolizers=Array(b);for(var c=0;c<b;++c)a.symbolizers[c]=this.symbolizers[c].clone()}else{a.symbolizer={};for(var d in this.symbolizer)b=this.symbolizer[d],c=typeof b,"object"===c?a.symbolizer[d]=OpenLayers.Util.extend({},b):"string"===c&&(a.symbolizer[d]=b)}a.filter=this.filter&&this.filter.clone();a.context=this.context&&OpenLayers.Util.extend({},
2354 this.context);return new OpenLayers.Rule(a)},CLASS_NAME:"OpenLayers.Rule"});OpenLayers.Filter.Spatial=OpenLayers.Class(OpenLayers.Filter,{type:null,property:null,value:null,distance:null,distanceUnits:null,evaluate:function(a){var b=!1;switch(this.type){case OpenLayers.Filter.Spatial.BBOX:case OpenLayers.Filter.Spatial.INTERSECTS:if(a.geometry){var c=this.value;"OpenLayers.Bounds"==this.value.CLASS_NAME&&(c=this.value.toGeometry());a.geometry.intersects(c)&&(b=!0)}break;default:throw Error("evaluate is not implemented for this filter type.");}return b},clone:function(){var a=
2355 OpenLayers.Util.applyDefaults({value:this.value&&this.value.clone&&this.value.clone()},this);return new OpenLayers.Filter.Spatial(a)},CLASS_NAME:"OpenLayers.Filter.Spatial"});OpenLayers.Filter.Spatial.BBOX="BBOX";OpenLayers.Filter.Spatial.INTERSECTS="INTERSECTS";OpenLayers.Filter.Spatial.DWITHIN="DWITHIN";OpenLayers.Filter.Spatial.WITHIN="WITHIN";OpenLayers.Filter.Spatial.CONTAINS="CONTAINS";OpenLayers.Format.SLD=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{profile:null,defaultVersion:"1.0.0",stringifyOutput:!0,namedLayersAsArray:!1,CLASS_NAME:"OpenLayers.Format.SLD"});OpenLayers.Symbolizer.Polygon=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Polygon"});OpenLayers.Format.GML.v2=OpenLayers.Class(OpenLayers.Format.GML.Base,{schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",initialize:function(a){OpenLayers.Format.GML.Base.prototype.initialize.apply(this,[a])},readers:{gml:OpenLayers.Util.applyDefaults({outerBoundaryIs:function(a,b){var c={};this.readChildNodes(a,c);b.outer=c.components[0]},innerBoundaryIs:function(a,b){var c={};this.readChildNodes(a,c);b.inner.push(c.components[0])},Box:function(a,b){var c=
2356 {};this.readChildNodes(a,c);b.components||(b.components=[]);var d=c.points[0],c=c.points[1];b.components.push(new OpenLayers.Bounds(d.x,d.y,c.x,c.y))}},OpenLayers.Format.GML.Base.prototype.readers.gml),feature:OpenLayers.Format.GML.Base.prototype.readers.feature,wfs:OpenLayers.Format.GML.Base.prototype.readers.wfs},write:function(a){a=this.writeNode(OpenLayers.Util.isArray(a)?"wfs:FeatureCollection":"gml:featureMember",a);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);
2357 return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{gml:OpenLayers.Util.applyDefaults({Point:function(a){var b=this.createElementNSPlus("gml:Point");this.writeNode("coordinates",[a],b);return b},coordinates:function(a){for(var b=a.length,c=Array(b),d,e=0;e<b;++e)d=a[e],c[e]=this.xy?d.x+","+d.y:d.y+","+d.x,void 0!=d.z&&(c[e]+=","+d.z);return this.createElementNSPlus("gml:coordinates",{attributes:{decimal:".",cs:",",ts:" "},value:1==b?c[0]:c.join(" ")})},LineString:function(a){var b=
2358 this.createElementNSPlus("gml:LineString");this.writeNode("coordinates",a.components,b);return b},Polygon:function(a){var b=this.createElementNSPlus("gml:Polygon");this.writeNode("outerBoundaryIs",a.components[0],b);for(var c=1;c<a.components.length;++c)this.writeNode("innerBoundaryIs",a.components[c],b);return b},outerBoundaryIs:function(a){var b=this.createElementNSPlus("gml:outerBoundaryIs");this.writeNode("LinearRing",a,b);return b},innerBoundaryIs:function(a){var b=this.createElementNSPlus("gml:innerBoundaryIs");
2359 this.writeNode("LinearRing",a,b);return b},LinearRing:function(a){var b=this.createElementNSPlus("gml:LinearRing");this.writeNode("coordinates",a.components,b);return b},Box:function(a){var b=this.createElementNSPlus("gml:Box");this.writeNode("coordinates",[{x:a.left,y:a.bottom},{x:a.right,y:a.top}],b);this.srsName&&b.setAttribute("srsName",this.srsName);return b}},OpenLayers.Format.GML.Base.prototype.writers.gml),feature:OpenLayers.Format.GML.Base.prototype.writers.feature,wfs:OpenLayers.Format.GML.Base.prototype.writers.wfs},
2360 CLASS_NAME:"OpenLayers.Format.GML.v2"});OpenLayers.Format.Filter.v1_0_0=OpenLayers.Class(OpenLayers.Format.GML.v2,OpenLayers.Format.Filter.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/ogc/filter/1.0.0/filter.xsd",initialize:function(a){OpenLayers.Format.GML.v2.prototype.initialize.apply(this,[a])},readers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsNotEqualTo:function(a,
2361 b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.NOT_EQUAL_TO});this.readChildNodes(a,c);b.filters.push(c)},PropertyIsLike:function(a,b){var c=new OpenLayers.Filter.Comparison({type:OpenLayers.Filter.Comparison.LIKE});this.readChildNodes(a,c);var d=a.getAttribute("wildCard"),e=a.getAttribute("singleChar"),f=a.getAttribute("escape");c.value2regex(d,e,f);b.filters.push(c)}},OpenLayers.Format.Filter.v1.prototype.readers.ogc),gml:OpenLayers.Format.GML.v2.prototype.readers.gml,
2362 feature:OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{ogc:OpenLayers.Util.applyDefaults({PropertyIsEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsNotEqualTo:function(a){var b=this.createElementNSPlus("ogc:PropertyIsNotEqualTo");this.writeNode("PropertyName",a,b);this.writeOgcExpression(a.value,b);return b},PropertyIsLike:function(a){var b=this.createElementNSPlus("ogc:PropertyIsLike",
2363 {attributes:{wildCard:"*",singleChar:".",escape:"!"}});this.writeNode("PropertyName",a,b);this.writeNode("Literal",a.regex2value(),b);return b},BBOX:function(a){var b=this.createElementNSPlus("ogc:BBOX");a.property&&this.writeNode("PropertyName",a,b);var c=this.writeNode("gml:Box",a.value,b);a.projection&&c.setAttribute("srsName",a.projection);return b}},OpenLayers.Format.Filter.v1.prototype.writers.ogc),gml:OpenLayers.Format.GML.v2.prototype.writers.gml,feature:OpenLayers.Format.GML.v2.prototype.writers.feature},
2364 writeSpatial:function(a,b){var c=this.createElementNSPlus("ogc:"+b);this.writeNode("PropertyName",a,c);if(a.value instanceof OpenLayers.Filter.Function)this.writeNode("Function",a.value,c);else{var d;d=a.value instanceof OpenLayers.Geometry?this.writeNode("feature:_geometry",a.value).firstChild:this.writeNode("gml:Box",a.value);a.projection&&d.setAttribute("srsName",a.projection);c.appendChild(d)}return c},CLASS_NAME:"OpenLayers.Format.Filter.v1_0_0"});OpenLayers.Format.WFST.v1_0_0=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,OpenLayers.Format.WFST.v1,{version:"1.0.0",srsNameInQuery:!1,schemaLocations:{wfs:"http://schemas.opengis.net/wfs/1.0.0/WFS-transaction.xsd"},initialize:function(a){OpenLayers.Format.Filter.v1_0_0.prototype.initialize.apply(this,[a]);OpenLayers.Format.WFST.v1.prototype.initialize.apply(this,[a])},readNode:function(a,b){return OpenLayers.Format.GML.v2.prototype.readNode.apply(this,[a,b])},readers:{wfs:OpenLayers.Util.applyDefaults({WFS_TransactionResponse:function(a,
2365 b){b.insertIds=[];b.success=!1;this.readChildNodes(a,b)},InsertResult:function(a,b){var c={fids:[]};this.readChildNodes(a,c);b.insertIds.push(c.fids[0])},TransactionResult:function(a,b){this.readChildNodes(a,b)},Status:function(a,b){this.readChildNodes(a,b)},SUCCESS:function(a,b){b.success=!0}},OpenLayers.Format.WFST.v1.prototype.readers.wfs),gml:OpenLayers.Format.GML.v2.prototype.readers.gml,feature:OpenLayers.Format.GML.v2.prototype.readers.feature,ogc:OpenLayers.Format.Filter.v1_0_0.prototype.readers.ogc},
2366 writers:{wfs:OpenLayers.Util.applyDefaults({Query:function(a){var a=OpenLayers.Util.extend({featureNS:this.featureNS,featurePrefix:this.featurePrefix,featureType:this.featureType,srsName:this.srsName,srsNameInQuery:this.srsNameInQuery},a),b=a.featurePrefix,c=this.createElementNSPlus("wfs:Query",{attributes:{typeName:(b?b+":":"")+a.featureType}});a.srsNameInQuery&&a.srsName&&c.setAttribute("srsName",a.srsName);a.featureNS&&c.setAttribute("xmlns:"+b,a.featureNS);if(a.propertyNames)for(var b=0,d=a.propertyNames.length;b<
2367 d;b++)this.writeNode("ogc:PropertyName",{property:a.propertyNames[b]},c);a.filter&&(this.setFilterProperty(a.filter),this.writeNode("ogc:Filter",a.filter,c));return c}},OpenLayers.Format.WFST.v1.prototype.writers.wfs),gml:OpenLayers.Format.GML.v2.prototype.writers.gml,feature:OpenLayers.Format.GML.v2.prototype.writers.feature,ogc:OpenLayers.Format.Filter.v1_0_0.prototype.writers.ogc},CLASS_NAME:"OpenLayers.Format.WFST.v1_0_0"});OpenLayers.ElementsIndexer=OpenLayers.Class({maxZIndex:null,order:null,indices:null,compare:null,initialize:function(a){this.compare=a?OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_Y_ORDER:OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER_DRAWING_ORDER;this.clear()},insert:function(a){this.exists(a)&&this.remove(a);var b=a.id;this.determineZIndex(a);for(var c=-1,d=this.order.length,e;1<d-c;)e=parseInt((c+d)/2),0<this.compare(this,a,OpenLayers.Util.getElement(this.order[e]))?c=e:d=e;this.order.splice(d,
2368 0,b);this.indices[b]=this.getZIndex(a);return this.getNextElement(d)},remove:function(a){var a=a.id,b=OpenLayers.Util.indexOf(this.order,a);0<=b&&(this.order.splice(b,1),delete this.indices[a],this.maxZIndex=0<this.order.length?this.indices[this.order[this.order.length-1]]:0)},clear:function(){this.order=[];this.indices={};this.maxZIndex=0},exists:function(a){return null!=this.indices[a.id]},getZIndex:function(a){return a._style.graphicZIndex},determineZIndex:function(a){var b=a._style.graphicZIndex;
2369 null==b?(b=this.maxZIndex,a._style.graphicZIndex=b):b>this.maxZIndex&&(this.maxZIndex=b)},getNextElement:function(a){a+=1;if(a<this.order.length){var b=OpenLayers.Util.getElement(this.order[a]);void 0==b&&(b=this.getNextElement(a));return b}return null},CLASS_NAME:"OpenLayers.ElementsIndexer"});
2370 OpenLayers.ElementsIndexer.IndexingMethods={Z_ORDER:function(a,b,c){var b=a.getZIndex(b),d=0;c&&(a=a.getZIndex(c),d=b-a);return d},Z_ORDER_DRAWING_ORDER:function(a,b,c){a=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(a,b,c);c&&0==a&&(a=1);return a},Z_ORDER_Y_ORDER:function(a,b,c){a=OpenLayers.ElementsIndexer.IndexingMethods.Z_ORDER(a,b,c);c&&0===a&&(b=c._boundsBottom-b._boundsBottom,a=0===b?1:b);return a}};
2371 OpenLayers.Renderer.Elements=OpenLayers.Class(OpenLayers.Renderer,{rendererRoot:null,root:null,vectorRoot:null,textRoot:null,xmlns:null,xOffset:0,indexer:null,BACKGROUND_ID_SUFFIX:"_background",LABEL_ID_SUFFIX:"_label",LABEL_OUTLINE_SUFFIX:"_outline",initialize:function(a,b){OpenLayers.Renderer.prototype.initialize.apply(this,arguments);this.rendererRoot=this.createRenderRoot();this.root=this.createRoot("_root");this.vectorRoot=this.createRoot("_vroot");this.textRoot=this.createRoot("_troot");this.root.appendChild(this.vectorRoot);
2372 this.root.appendChild(this.textRoot);this.rendererRoot.appendChild(this.root);this.container.appendChild(this.rendererRoot);if(b&&(b.zIndexing||b.yOrdering))this.indexer=new OpenLayers.ElementsIndexer(b.yOrdering)},destroy:function(){this.clear();this.xmlns=this.root=this.rendererRoot=null;OpenLayers.Renderer.prototype.destroy.apply(this,arguments)},clear:function(){var a,b=this.vectorRoot;if(b)for(;a=b.firstChild;)b.removeChild(a);if(b=this.textRoot)for(;a=b.firstChild;)b.removeChild(a);this.indexer&&
2373 this.indexer.clear()},setExtent:function(a,b){var c=OpenLayers.Renderer.prototype.setExtent.apply(this,arguments),d=this.getResolution();if(this.map.baseLayer&&this.map.baseLayer.wrapDateLine){var e,f=a.getWidth()/this.map.getExtent().getWidth(),a=a.scale(1/f),f=this.map.getMaxExtent();f.right>a.left&&f.right<a.right?e=!0:f.left>a.left&&f.left<a.right&&(e=!1);if(e!==this.rightOfDateLine||b)c=!1,this.xOffset=!0===e?f.getWidth()/d:0;this.rightOfDateLine=e}return c},getNodeType:function(){},drawGeometry:function(a,
2374 b,c){var d=a.CLASS_NAME,e=!0;if("OpenLayers.Geometry.Collection"==d||"OpenLayers.Geometry.MultiPoint"==d||"OpenLayers.Geometry.MultiLineString"==d||"OpenLayers.Geometry.MultiPolygon"==d){for(var d=0,f=a.components.length;d<f;d++)e=this.drawGeometry(a.components[d],b,c)&&e;return e}d=e=!1;"none"!=b.display&&(b.backgroundGraphic?this.redrawBackgroundNode(a.id,a,b,c):d=!0,e=this.redrawNode(a.id,a,b,c));if(!1==e&&(b=document.getElementById(a.id)))b._style.backgroundGraphic&&(d=!0),b.parentNode.removeChild(b);
2375 d&&(b=document.getElementById(a.id+this.BACKGROUND_ID_SUFFIX))&&b.parentNode.removeChild(b);return e},redrawNode:function(a,b,c,d){c=this.applyDefaultSymbolizer(c);a=this.nodeFactory(a,this.getNodeType(b,c));a._featureId=d;a._boundsBottom=b.getBounds().bottom;a._geometryClass=b.CLASS_NAME;a._style=c;b=this.drawGeometryNode(a,b,c);if(!1===b)return!1;a=b.node;this.indexer?(c=this.indexer.insert(a))?this.vectorRoot.insertBefore(a,c):this.vectorRoot.appendChild(a):a.parentNode!==this.vectorRoot&&this.vectorRoot.appendChild(a);
2376 this.postDraw(a);return b.complete},redrawBackgroundNode:function(a,b,c){c=OpenLayers.Util.extend({},c);c.externalGraphic=c.backgroundGraphic;c.graphicXOffset=c.backgroundXOffset;c.graphicYOffset=c.backgroundYOffset;c.graphicZIndex=c.backgroundGraphicZIndex;c.graphicWidth=c.backgroundWidth||c.graphicWidth;c.graphicHeight=c.backgroundHeight||c.graphicHeight;c.backgroundGraphic=null;c.backgroundXOffset=null;c.backgroundYOffset=null;c.backgroundGraphicZIndex=null;return this.redrawNode(a+this.BACKGROUND_ID_SUFFIX,
2377 b,c,null)},drawGeometryNode:function(a,b,c){var c=c||a._style,d={isFilled:void 0===c.fill?!0:c.fill,isStroked:void 0===c.stroke?!!c.strokeWidth:c.stroke},e;switch(b.CLASS_NAME){case "OpenLayers.Geometry.Point":!1===c.graphic&&(d.isFilled=!1,d.isStroked=!1);e=this.drawPoint(a,b);break;case "OpenLayers.Geometry.LineString":d.isFilled=!1;e=this.drawLineString(a,b);break;case "OpenLayers.Geometry.LinearRing":e=this.drawLinearRing(a,b);break;case "OpenLayers.Geometry.Polygon":e=this.drawPolygon(a,b);break;
2378 case "OpenLayers.Geometry.Rectangle":e=this.drawRectangle(a,b)}a._options=d;return!1!=e?{node:this.setStyle(a,c,d,b),complete:e}:!1},postDraw:function(){},drawPoint:function(){},drawLineString:function(){},drawLinearRing:function(){},drawPolygon:function(){},drawRectangle:function(){},drawCircle:function(){},removeText:function(a){var b=document.getElementById(a+this.LABEL_ID_SUFFIX);b&&this.textRoot.removeChild(b);(a=document.getElementById(a+this.LABEL_OUTLINE_SUFFIX))&&this.textRoot.removeChild(a)},
2379 getFeatureIdFromEvent:function(a){var b=a.target,c=b&&b.correspondingUseElement;return(c?c:b||a.srcElement)._featureId},eraseGeometry:function(a,b){if("OpenLayers.Geometry.MultiPoint"==a.CLASS_NAME||"OpenLayers.Geometry.MultiLineString"==a.CLASS_NAME||"OpenLayers.Geometry.MultiPolygon"==a.CLASS_NAME||"OpenLayers.Geometry.Collection"==a.CLASS_NAME)for(var c=0,d=a.components.length;c<d;c++)this.eraseGeometry(a.components[c],b);else if((c=OpenLayers.Util.getElement(a.id))&&c.parentNode)if(c.geometry&&
2380 (c.geometry.destroy(),c.geometry=null),c.parentNode.removeChild(c),this.indexer&&this.indexer.remove(c),c._style.backgroundGraphic)(c=OpenLayers.Util.getElement(a.id+this.BACKGROUND_ID_SUFFIX))&&c.parentNode&&c.parentNode.removeChild(c)},nodeFactory:function(a,b){var c=OpenLayers.Util.getElement(a);c?this.nodeTypeCompare(c,b)||(c.parentNode.removeChild(c),c=this.nodeFactory(a,b)):c=this.createNode(b,a);return c},nodeTypeCompare:function(){},createNode:function(){},moveRoot:function(a){var b=this.root;
2381 a.root.parentNode==this.rendererRoot&&(b=a.root);b.parentNode.removeChild(b);a.rendererRoot.appendChild(b)},getRenderLayerId:function(){return this.root.parentNode.parentNode.id},isComplexSymbol:function(a){return"circle"!=a&&!!a},CLASS_NAME:"OpenLayers.Renderer.Elements"});OpenLayers.Control.ArgParser=OpenLayers.Class(OpenLayers.Control,{center:null,zoom:null,layers:null,displayProjection:null,getParameters:function(a){var a=a||window.location.href,b=OpenLayers.Util.getParameters(a),c=a.indexOf("#");0<c&&(a="?"+a.substring(c+1,a.length),OpenLayers.Util.extend(b,OpenLayers.Util.getParameters(a)));return b},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var b=0,c=this.map.controls.length;b<c;b++){var d=this.map.controls[b];if(d!=this&&
2382 "OpenLayers.Control.ArgParser"==d.CLASS_NAME){d.displayProjection!=this.displayProjection&&(this.displayProjection=d.displayProjection);break}}if(b==this.map.controls.length&&(b=this.getParameters(),b.layers&&(this.layers=b.layers,this.map.events.register("addlayer",this,this.configureLayers),this.configureLayers()),b.lat&&b.lon))this.center=new OpenLayers.LonLat(parseFloat(b.lon),parseFloat(b.lat)),b.zoom&&(this.zoom=parseFloat(b.zoom)),this.map.events.register("changebaselayer",this,this.setCenter),
2383 this.setCenter()},setCenter:function(){this.map.baseLayer&&(this.map.events.unregister("changebaselayer",this,this.setCenter),this.displayProjection&&this.center.transform(this.displayProjection,this.map.getProjectionObject()),this.map.setCenter(this.center,this.zoom))},configureLayers:function(){if(this.layers.length==this.map.layers.length){this.map.events.unregister("addlayer",this,this.configureLayers);for(var a=0,b=this.layers.length;a<b;a++){var c=this.map.layers[a],d=this.layers.charAt(a);
2384 "B"==d?this.map.setBaseLayer(c):("T"==d||"F"==d)&&c.setVisibility("T"==d)}}},CLASS_NAME:"OpenLayers.Control.ArgParser"});OpenLayers.Control.Permalink=OpenLayers.Class(OpenLayers.Control,{argParserClass:OpenLayers.Control.ArgParser,element:null,anchor:!1,base:"",displayProjection:null,initialize:function(a,b,c){null!==a&&"object"==typeof a&&!OpenLayers.Util.isElement(a)?(this.base=document.location.href,OpenLayers.Control.prototype.initialize.apply(this,[a]),null!=this.element&&(this.element=OpenLayers.Util.getElement(this.element))):(OpenLayers.Control.prototype.initialize.apply(this,[c]),this.element=OpenLayers.Util.getElement(a),
2385 this.base=b||document.location.href)},destroy:function(){this.element&&this.element.parentNode==this.div&&(this.div.removeChild(this.element),this.element=null);this.map&&this.map.events.unregister("moveend",this,this.updateLink);OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);for(var b=0,c=this.map.controls.length;b<c;b++){var d=this.map.controls[b];if(d.CLASS_NAME==this.argParserClass.CLASS_NAME){d.displayProjection!=
2386 this.displayProjection&&(this.displayProjection=d.displayProjection);break}}b==this.map.controls.length&&this.map.addControl(new this.argParserClass({displayProjection:this.displayProjection}))},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);!this.element&&!this.anchor&&(this.element=document.createElement("a"),this.element.innerHTML=OpenLayers.i18n("Permalink"),this.element.href="",this.div.appendChild(this.element));this.map.events.on({moveend:this.updateLink,changelayer:this.updateLink,
2387 changebaselayer:this.updateLink,scope:this});this.updateLink();return this.div},updateLink:function(){var a=this.anchor?"#":"?",b=this.base;-1!=b.indexOf(a)&&(b=b.substring(0,b.indexOf(a)));b+=a+OpenLayers.Util.getParameterString(this.createParams());this.anchor&&!this.element?window.location.href=b:this.element.href=b},createParams:function(a,b,c){var a=a||this.map.getCenter(),d=OpenLayers.Util.getParameters(this.base);if(a){d.zoom=b||this.map.getZoom();b=a.lat;a=a.lon;this.displayProjection&&(b=
2388 OpenLayers.Projection.transform({x:a,y:b},this.map.getProjectionObject(),this.displayProjection),a=b.x,b=b.y);d.lat=Math.round(1E5*b)/1E5;d.lon=Math.round(1E5*a)/1E5;c=c||this.map.layers;d.layers="";a=0;for(b=c.length;a<b;a++){var e=c[a];d.layers=e.isBaseLayer?d.layers+(e==this.map.baseLayer?"B":"0"):d.layers+(e.getVisibility()?"T":"F")}}return d},CLASS_NAME:"OpenLayers.Control.Permalink"});OpenLayers.Layer.TMS=OpenLayers.Class(OpenLayers.Layer.Grid,{serviceVersion:"1.0.0",layername:null,type:null,isBaseLayer:!0,tileOrigin:null,serverResolutions:null,zoomOffset:0,initialize:function(a,b,c){var d=[];d.push(a,b,{},c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,d)},clone:function(a){null==a&&(a=new OpenLayers.Layer.TMS(this.name,this.url,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var a=this.adjustBounds(a),b=this.getServerResolution(),
2389 c=Math.round((a.left-this.tileOrigin.lon)/(b*this.tileSize.w)),a=Math.round((a.bottom-this.tileOrigin.lat)/(b*this.tileSize.h)),c=this.serviceVersion+"/"+this.layername+"/"+this.getServerZoom()+"/"+c+"/"+a+"."+this.type,a=this.url;OpenLayers.Util.isArray(a)&&(a=this.selectUrl(c,a));return a+c},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.bottom))},CLASS_NAME:"OpenLayers.Layer.TMS"});OpenLayers.Strategy.Fixed=OpenLayers.Class(OpenLayers.Strategy,{preload:!1,activate:function(){if(OpenLayers.Strategy.prototype.activate.apply(this,arguments)){this.layer.events.on({refresh:this.load,scope:this});if(!0==this.layer.visibility||this.preload)this.load();else this.layer.events.on({visibilitychanged:this.load,scope:this});return!0}return!1},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({refresh:this.load,visibilitychanged:this.load,
2390 scope:this});return a},load:function(a){var b=this.layer;b.events.triggerEvent("loadstart");b.protocol.read(OpenLayers.Util.applyDefaults({callback:OpenLayers.Function.bind(this.merge,this,b.map.getProjectionObject()),filter:b.filter},a));b.events.un({visibilitychanged:this.load,scope:this})},merge:function(a,b){var c=this.layer;c.destroyFeatures();var d=b.features;if(d&&0<d.length){if(!a.equals(c.projection))for(var e,f=0,g=d.length;f<g;++f)(e=d[f].geometry)&&e.transform(c.projection,a);c.addFeatures(d)}c.events.triggerEvent("loadend")},
2391 CLASS_NAME:"OpenLayers.Strategy.Fixed"});OpenLayers.Control.Zoom=OpenLayers.Class(OpenLayers.Control,{zoomInText:"+",zoomInId:"olZoomInLink",zoomOutText:"-",zoomOutId:"olZoomOutLink",draw:function(){var a=OpenLayers.Control.prototype.draw.apply(this),b=this.getOrCreateLinks(a),c=b.zoomIn,b=b.zoomOut,d=this.map.events;b.parentNode!==a&&(d=this.events,d.attachToElement(b.parentNode));d.register("buttonclick",this,this.onZoomClick);this.zoomInLink=c;this.zoomOutLink=b;return a},getOrCreateLinks:function(a){var b=document.getElementById(this.zoomInId),
2392 c=document.getElementById(this.zoomOutId);b||(b=document.createElement("a"),b.href="#zoomIn",b.appendChild(document.createTextNode(this.zoomInText)),b.className="olControlZoomIn",a.appendChild(b));OpenLayers.Element.addClass(b,"olButton");c||(c=document.createElement("a"),c.href="#zoomOut",c.appendChild(document.createTextNode(this.zoomOutText)),c.className="olControlZoomOut",a.appendChild(c));OpenLayers.Element.addClass(c,"olButton");return{zoomIn:b,zoomOut:c}},onZoomClick:function(a){a=a.buttonElement;
2393 a===this.zoomInLink?this.map.zoomIn():a===this.zoomOutLink&&this.map.zoomOut()},destroy:function(){this.map&&this.map.events.unregister("buttonclick",this,this.onZoomClick);delete this.zoomInLink;delete this.zoomOutLink;OpenLayers.Control.prototype.destroy.apply(this)},CLASS_NAME:"OpenLayers.Control.Zoom"});OpenLayers.Layer.PointTrack=OpenLayers.Class(OpenLayers.Layer.Vector,{dataFrom:null,styleFrom:null,addNodes:function(a,b){if(2>a.length)throw Error("At least two point features have to be added to create a line from");for(var c=Array(a.length-1),d,e,f,g=0,h=a.length;g<h;g++){d=a[g];if(f=d.geometry){if("OpenLayers.Geometry.Point"!=f.CLASS_NAME)throw new TypeError("Only features with point geometries are supported.");}else f=d.lonlat,f=new OpenLayers.Geometry.Point(f.lon,f.lat);if(0<g){d=null!=this.dataFrom?
2394 a[g+this.dataFrom].data||a[g+this.dataFrom].attributes:null;var i=null!=this.styleFrom?a[g+this.styleFrom].style:null;e=new OpenLayers.Geometry.LineString([e,f]);c[g-1]=new OpenLayers.Feature.Vector(e,d,i)}e=f}this.addFeatures(c,b)},CLASS_NAME:"OpenLayers.Layer.PointTrack"});OpenLayers.Layer.PointTrack.SOURCE_NODE=-1;OpenLayers.Layer.PointTrack.TARGET_NODE=0;OpenLayers.Layer.PointTrack.dataFrom={SOURCE_NODE:-1,TARGET_NODE:0};OpenLayers.Protocol.WFS=function(a){var a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.WFS.DEFAULTS),b=OpenLayers.Protocol.WFS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported WFS version: "+a.version;return new b(a)};
2395 OpenLayers.Protocol.WFS.fromWMSLayer=function(a,b){var c,d;c=a.params.LAYERS;c=(OpenLayers.Util.isArray(c)?c[0]:c).split(":");1<c.length&&(d=c[0]);c=c.pop();d={url:a.url,featureType:c,featurePrefix:d,srsName:a.projection&&a.projection.getCode()||a.map&&a.map.getProjectionObject().getCode(),version:"1.1.0"};return new OpenLayers.Protocol.WFS(OpenLayers.Util.applyDefaults(b,d))};OpenLayers.Protocol.WFS.DEFAULTS={version:"1.0.0"};OpenLayers.Layer.Markers=OpenLayers.Class(OpenLayers.Layer,{isBaseLayer:!1,markers:null,drawn:!1,initialize:function(a,b){OpenLayers.Layer.prototype.initialize.apply(this,arguments);this.markers=[]},destroy:function(){this.clearMarkers();this.markers=null;OpenLayers.Layer.prototype.destroy.apply(this,arguments)},setOpacity:function(a){if(a!=this.opacity){this.opacity=a;for(var a=0,b=this.markers.length;a<b;a++)this.markers[a].setOpacity(this.opacity)}},moveTo:function(a,b,c){OpenLayers.Layer.prototype.moveTo.apply(this,
2396 arguments);if(b||!this.drawn){for(var d=0,e=this.markers.length;d<e;d++)this.drawMarker(this.markers[d]);this.drawn=!0}},addMarker:function(a){this.markers.push(a);1>this.opacity&&a.setOpacity(this.opacity);this.map&&this.map.getExtent()&&(a.map=this.map,this.drawMarker(a))},removeMarker:function(a){this.markers&&this.markers.length&&(OpenLayers.Util.removeItem(this.markers,a),a.erase())},clearMarkers:function(){if(null!=this.markers)for(;0<this.markers.length;)this.removeMarker(this.markers[0])},
2397 drawMarker:function(a){var b=this.map.getLayerPxFromLonLat(a.lonlat);null==b?a.display(!1):a.isDrawn()?a.icon&&a.icon.moveTo(b):this.div.appendChild(a.draw(b))},getDataExtent:function(){var a=null;if(this.markers&&0<this.markers.length)for(var a=new OpenLayers.Bounds,b=0,c=this.markers.length;b<c;b++)a.extend(this.markers[b].lonlat);return a},CLASS_NAME:"OpenLayers.Layer.Markers"});OpenLayers.Control.Pan=OpenLayers.Class(OpenLayers.Control,{slideFactor:50,slideRatio:null,direction:null,type:OpenLayers.Control.TYPE_BUTTON,initialize:function(a,b){this.direction=a;this.CLASS_NAME+=this.direction;OpenLayers.Control.prototype.initialize.apply(this,[b])},trigger:function(){var a=OpenLayers.Function.bind(function(a){return this.slideRatio?this.map.getSize()[a]*this.slideRatio:this.slideFactor},this);switch(this.direction){case OpenLayers.Control.Pan.NORTH:this.map.pan(0,-a("h"));
2398 break;case OpenLayers.Control.Pan.SOUTH:this.map.pan(0,a("h"));break;case OpenLayers.Control.Pan.WEST:this.map.pan(-a("w"),0);break;case OpenLayers.Control.Pan.EAST:this.map.pan(a("w"),0)}},CLASS_NAME:"OpenLayers.Control.Pan"});OpenLayers.Control.Pan.NORTH="North";OpenLayers.Control.Pan.SOUTH="South";OpenLayers.Control.Pan.EAST="East";OpenLayers.Control.Pan.WEST="West";OpenLayers.Format.CSWGetDomain=function(a){var a=OpenLayers.Util.applyDefaults(a,OpenLayers.Format.CSWGetDomain.DEFAULTS),b=OpenLayers.Format.CSWGetDomain["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSWGetDomain version: "+a.version;return new b(a)};OpenLayers.Format.CSWGetDomain.DEFAULTS={version:"2.0.2"};OpenLayers.Format.CSWGetDomain.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance",csw:"http://www.opengis.net/cat/csw/2.0.2"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",PropertyName:null,ParameterName:null,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==
2399 a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{csw:{GetDomainResponse:function(a,b){this.readChildNodes(a,b)},DomainValues:function(a,b){OpenLayers.Util.isArray(b.DomainValues)||(b.DomainValues=[]);for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;this.readChildNodes(a,d);b.DomainValues.push(d)},PropertyName:function(a,b){b.PropertyName=this.getChildValue(a)},ParameterName:function(a,b){b.ParameterName=this.getChildValue(a)},ListOfValues:function(a,
2400 b){OpenLayers.Util.isArray(b.ListOfValues)||(b.ListOfValues=[]);this.readChildNodes(a,b.ListOfValues)},Value:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.push({Value:d})},ConceptualScheme:function(a,b){b.ConceptualScheme={};this.readChildNodes(a,b.ConceptualScheme)},Name:function(a,b){b.Name=this.getChildValue(a)},Document:function(a,b){b.Document=this.getChildValue(a)},Authority:function(a,b){b.Authority=this.getChildValue(a)},
2401 RangeOfValues:function(a,b){b.RangeOfValues={};this.readChildNodes(a,b.RangeOfValues)},MinValue:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.MinValue=d},MaxValue:function(a,b){for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]=c[e].nodeValue;d.value=this.getChildValue(a);b.MaxValue=d}}},write:function(a){a=this.writeNode("csw:GetDomain",a);return OpenLayers.Format.XML.prototype.write.apply(this,[a])},writers:{csw:{GetDomain:function(a){var b=
2402 this.createElementNSPlus("csw:GetDomain",{attributes:{service:"CSW",version:this.version}});if(a.PropertyName||this.PropertyName)this.writeNode("csw:PropertyName",a.PropertyName||this.PropertyName,b);else if(a.ParameterName||this.ParameterName)this.writeNode("csw:ParameterName",a.ParameterName||this.ParameterName,b);this.readChildNodes(b,a);return b},PropertyName:function(a){return this.createElementNSPlus("csw:PropertyName",{value:a})},ParameterName:function(a){return this.createElementNSPlus("csw:ParameterName",
2403 {value:a})}}},CLASS_NAME:"OpenLayers.Format.CSWGetDomain.v2_0_2"});OpenLayers.Format.ArcXML.Features=OpenLayers.Class(OpenLayers.Format.XML,{read:function(a){return(new OpenLayers.Format.ArcXML).read(a).features.feature}});OpenLayers.Control.Snapping=OpenLayers.Class(OpenLayers.Control,{DEFAULTS:{tolerance:10,node:!0,edge:!0,vertex:!0},greedy:!0,precedence:["node","vertex","edge"],resolution:null,geoToleranceCache:null,layer:null,feature:null,point:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.options=a||{};this.options.layer&&this.setLayer(this.options.layer);a=OpenLayers.Util.extend({},this.options.defaults);this.defaults=OpenLayers.Util.applyDefaults(a,this.DEFAULTS);this.setTargets(this.options.targets);
2404 0===this.targets.length&&this.layer&&this.addTargetLayer(this.layer);this.geoToleranceCache={}},setLayer:function(a){this.active?(this.deactivate(),this.layer=a,this.activate()):this.layer=a},setTargets:function(a){this.targets=[];if(a&&a.length)for(var b,c=0,d=a.length;c<d;++c)b=a[c],b instanceof OpenLayers.Layer.Vector?this.addTargetLayer(b):this.addTarget(b)},addTargetLayer:function(a){this.addTarget({layer:a})},addTarget:function(a){a=OpenLayers.Util.applyDefaults(a,this.defaults);a.nodeTolerance=
2405 a.nodeTolerance||a.tolerance;a.vertexTolerance=a.vertexTolerance||a.tolerance;a.edgeTolerance=a.edgeTolerance||a.tolerance;this.targets.push(a)},removeTargetLayer:function(a){for(var b,c=this.targets.length-1;0<=c;--c)b=this.targets[c],b.layer===a&&this.removeTarget(b)},removeTarget:function(a){return OpenLayers.Util.removeItem(this.targets,a)},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a&&this.layer&&this.layer.events)this.layer.events.on({sketchstarted:this.onSketchModified,
2406 sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.call(this);a&&this.layer&&this.layer.events&&this.layer.events.un({sketchstarted:this.onSketchModified,sketchmodified:this.onSketchModified,vertexmodified:this.onVertexModified,scope:this});this.point=this.feature=null;return a},onSketchModified:function(a){this.feature=a.feature;this.considerSnapping(a.vertex,a.vertex)},onVertexModified:function(a){this.feature=
2407 a.feature;var b=this.layer.map.getLonLatFromViewPortPx(a.pixel);this.considerSnapping(a.vertex,new OpenLayers.Geometry.Point(b.lon,b.lat))},considerSnapping:function(a,b){for(var c={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY,x:null,y:null},d=!1,e,f,g=0,h=this.targets.length;g<h;++g)if(f=this.targets[g],e=this.testTarget(f,b))if(this.greedy){c=e;c.target=f;d=!0;break}else if(e.rank<c.rank||e.rank===c.rank&&e.dist<c.dist)c=e,c.target=f,d=!0;d&&(!1!==this.events.triggerEvent("beforesnap",
2408 {point:a,x:c.x,y:c.y,distance:c.dist,layer:c.target.layer,snapType:this.precedence[c.rank]})?(a.x=c.x,a.y=c.y,this.point=a,this.events.triggerEvent("snap",{point:a,snapType:this.precedence[c.rank],layer:c.target.layer,distance:c.dist})):d=!1);this.point&&!d&&(a.x=b.x,a.y=b.y,this.point=null,this.events.triggerEvent("unsnap",{point:a}))},testTarget:function(a,b){var c=this.layer.map.getResolution();if("minResolution"in a&&c<a.minResolution||"maxResolution"in a&&c>=a.maxResolution)return null;for(var c=
2409 {node:this.getGeoTolerance(a.nodeTolerance,c),vertex:this.getGeoTolerance(a.vertexTolerance,c),edge:this.getGeoTolerance(a.edgeTolerance,c)},d=Math.max(c.node,c.vertex,c.edge),e={rank:Number.POSITIVE_INFINITY,dist:Number.POSITIVE_INFINITY},f=!1,g=a.layer.features,h,i,j,k,l,m,n=this.precedence.length,o=new OpenLayers.LonLat(b.x,b.y),p=0,q=g.length;p<q;++p)if(h=g[p],h!==this.feature&&(!h._sketch&&h.state!==OpenLayers.State.DELETE&&(!a.filter||a.filter.evaluate(h)))&&h.atPoint(o,d,d))for(var r=0,s=Math.min(e.rank+
2410 1,n);r<s;++r)if(i=this.precedence[r],a[i])if("edge"===i){if(j=h.geometry.distanceTo(b,{details:!0}),l=j.distance,l<=c[i]&&l<e.dist){e={rank:r,dist:l,x:j.x0,y:j.y0};f=!0;break}}else{j=h.geometry.getVertices("node"===i);m=!1;for(var t=0,u=j.length;t<u;++t)if(k=j[t],l=k.distanceTo(b),l<=c[i]&&(r<e.rank||r===e.rank&&l<e.dist))e={rank:r,dist:l,x:k.x,y:k.y},m=f=!0;if(m)break}return f?e:null},getGeoTolerance:function(a,b){b!==this.resolution&&(this.resolution=b,this.geoToleranceCache={});var c=this.geoToleranceCache[a];
2411 void 0===c&&(c=a*b,this.geoToleranceCache[a]=c);return c},destroy:function(){this.active&&this.deactivate();delete this.layer;delete this.targets;OpenLayers.Control.prototype.destroy.call(this)},CLASS_NAME:"OpenLayers.Control.Snapping"});OpenLayers.Date={toISOString:function(){if("toISOString"in Date.prototype)return function(a){return a.toISOString()};var a=function(a,c){for(var d=a+"";d.length<c;)d="0"+d;return d};return function(b){return isNaN(b.getTime())?"Invalid Date":b.getUTCFullYear()+"-"+a(b.getUTCMonth()+1,2)+"-"+a(b.getUTCDate(),2)+"T"+a(b.getUTCHours(),2)+":"+a(b.getUTCMinutes(),2)+":"+a(b.getUTCSeconds(),2)+"."+a(b.getUTCMilliseconds(),3)+"Z"}}(),parse:function(a){var b;if((a=a.match(/^(?:(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?)?(?:(?:T(\d{1,2}):(\d{2}):(\d{2}(?:\.\d+)?)(Z|(?:[+-]\d{1,2}(?::(\d{2}))?)))|Z)?$/))&&
2412 (a[1]||a[7])){b=parseInt(a[1],10)||0;var c=parseInt(a[2],10)-1||0,d=parseInt(a[3],10)||1;b=new Date(Date.UTC(b,c,d));if(c=a[7]){var d=parseInt(a[4],10),e=parseInt(a[5],10),f=parseFloat(a[6]),g=f|0,f=Math.round(1E3*(f-g));b.setUTCHours(d,e,g,f);"Z"!==c&&(c=parseInt(c,10),a=parseInt(a[8],10)||0,b=new Date(b.getTime()+-1E3*(60*60*c+60*a)))}}else b=new Date("invalid");return b}};(function(){function a(){this._object=f&&!i?new f:new window.ActiveXObject("Microsoft.XMLHTTP");this._listeners=[]}function b(){return new a}function c(a){b.onreadystatechange&&b.onreadystatechange.apply(a);a.dispatchEvent({type:"readystatechange",bubbles:!1,cancelable:!1,timeStamp:new Date+0})}function d(a){try{a.responseText=a._object.responseText}catch(b){}try{var c;var d=a._object,e=d.responseXML,f=d.responseText;h&&(f&&e&&!e.documentElement&&d.getResponseHeader("Content-Type").match(/[^\/]+\/[^\+]+\+xml/))&&
2413 (e=new window.ActiveXObject("Microsoft.XMLDOM"),e.async=!1,e.validateOnParse=!1,e.loadXML(f));c=e&&(h&&0!=e.parseError||!e.documentElement||e.documentElement&&"parsererror"==e.documentElement.tagName)?null:e;a.responseXML=c}catch(g){}try{a.status=a._object.status}catch(i){}try{a.statusText=a._object.statusText}catch(r){}}function e(a){a._object.onreadystatechange=new window.Function}var f=window.XMLHttpRequest,g=!!window.controllers,h=window.document.all&&!window.opera,i=h&&window.navigator.userAgent.match(/MSIE 7.0/);
2414 b.prototype=a.prototype;g&&f.wrapped&&(b.wrapped=f.wrapped);b.UNSENT=0;b.OPENED=1;b.HEADERS_RECEIVED=2;b.LOADING=3;b.DONE=4;b.prototype.readyState=b.UNSENT;b.prototype.responseText="";b.prototype.responseXML=null;b.prototype.status=0;b.prototype.statusText="";b.prototype.priority="NORMAL";b.prototype.onreadystatechange=null;b.onreadystatechange=null;b.onopen=null;b.onsend=null;b.onabort=null;b.prototype.open=function(a,f,i,m,n){delete this._headers;arguments.length<3&&(i=true);this._async=i;var o=
2415 this,p=this.readyState,q;if(h&&i){q=function(){if(p!=b.DONE){e(o);o.abort()}};window.attachEvent("onunload",q)}b.onopen&&b.onopen.apply(this,arguments);arguments.length>4?this._object.open(a,f,i,m,n):arguments.length>3?this._object.open(a,f,i,m):this._object.open(a,f,i);this.readyState=b.OPENED;c(this);this._object.onreadystatechange=function(){if(!g||i){o.readyState=o._object.readyState;d(o);if(o._aborted)o.readyState=b.UNSENT;else{if(o.readyState==b.DONE){delete o._data;e(o);h&&i&&window.detachEvent("onunload",
2416 q)}p!=o.readyState&&c(o);p=o.readyState}}}};b.prototype.send=function(a){b.onsend&&b.onsend.apply(this,arguments);arguments.length||(a=null);if(a&&a.nodeType){a=window.XMLSerializer?(new window.XMLSerializer).serializeToString(a):a.xml;this._headers["Content-Type"]||this._object.setRequestHeader("Content-Type","application/xml")}this._data=a;a:{this._object.send(this._data);if(g&&!this._async){this.readyState=b.OPENED;for(d(this);this.readyState<b.DONE;){this.readyState++;c(this);if(this._aborted)break a}}}};
2417 b.prototype.abort=function(){b.onabort&&b.onabort.apply(this,arguments);if(this.readyState>b.UNSENT)this._aborted=true;this._object.abort();e(this);this.readyState=b.UNSENT;delete this._data};b.prototype.getAllResponseHeaders=function(){return this._object.getAllResponseHeaders()};b.prototype.getResponseHeader=function(a){return this._object.getResponseHeader(a)};b.prototype.setRequestHeader=function(a,b){if(!this._headers)this._headers={};this._headers[a]=b;return this._object.setRequestHeader(a,
2418 b)};b.prototype.addEventListener=function(a,b,c){for(var d=0,e;e=this._listeners[d];d++)if(e[0]==a&&e[1]==b&&e[2]==c)return;this._listeners.push([a,b,c])};b.prototype.removeEventListener=function(a,b,c){for(var d=0,e;e=this._listeners[d];d++)if(e[0]==a&&e[1]==b&&e[2]==c)break;e&&this._listeners.splice(d,1)};b.prototype.dispatchEvent=function(a){a={type:a.type,target:this,currentTarget:this,eventPhase:2,bubbles:a.bubbles,cancelable:a.cancelable,timeStamp:a.timeStamp,stopPropagation:function(){},preventDefault:function(){},
2419 initEvent:function(){}};a.type=="readystatechange"&&this.onreadystatechange&&(this.onreadystatechange.handleEvent||this.onreadystatechange).apply(this,[a]);for(var b=0,c;c=this._listeners[b];b++)c[0]==a.type&&!c[2]&&(c[1].handleEvent||c[1]).apply(this,[a])};b.prototype.toString=function(){return"[object XMLHttpRequest]"};b.toString=function(){return"[XMLHttpRequest]"};window.Function.prototype.apply||(window.Function.prototype.apply=function(a,b){b||(b=[]);a.__func=this;a.__func(b[0],b[1],b[2],b[3],
2420 b[4]);delete a.__func});OpenLayers.Request.XMLHttpRequest=b})();OpenLayers.Format.KML=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{kml:"http://www.opengis.net/kml/2.2",gx:"http://www.google.com/kml/ext/2.2"},kmlns:"http://earth.google.com/kml/2.0",placemarksDesc:"No description available",foldersName:"OpenLayers export",foldersDesc:"Exported on "+new Date,extractAttributes:!0,kvpAttributes:!1,extractStyles:!1,extractTracks:!1,trackAttributes:null,internalns:null,features:null,styles:null,styleBaseUrl:"",fetched:null,maxDepth:0,initialize:function(a){this.regExes=
2421 {trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g,kmlColor:/(\w{2})(\w{2})(\w{2})(\w{2})/,kmlIconPalette:/root:\/\/icons\/palette-(\d+)(\.\w+)/,straightBracket:/\$\[(.*?)\]/g};this.externalProjection=new OpenLayers.Projection("EPSG:4326");OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){this.features=[];this.styles={};this.fetched={};return this.parseData(a,{depth:0,styleBaseUrl:this.styleBaseUrl})},parseData:function(a,b){"string"==typeof a&&
2422 (a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));for(var c=["Link","NetworkLink","Style","StyleMap","Placemark"],d=0,e=c.length;d<e;++d){var f=c[d],g=this.getElementsByTagNameNS(a,"*",f);if(0!=g.length)switch(f.toLowerCase()){case "link":case "networklink":this.parseLinks(g,b);break;case "style":this.extractStyles&&this.parseStyles(g,b);break;case "stylemap":this.extractStyles&&this.parseStyleMaps(g,b);break;case "placemark":this.parseFeatures(g,b)}}return this.features},parseLinks:function(a,
2423 b){if(b.depth>=this.maxDepth)return!1;var c=OpenLayers.Util.extend({},b);c.depth++;for(var d=0,e=a.length;d<e;d++){var f=this.parseProperty(a[d],"*","href");f&&!this.fetched[f]&&(this.fetched[f]=!0,(f=this.fetchLink(f))&&this.parseData(f,c))}},fetchLink:function(a){if(a=OpenLayers.Request.GET({url:a,async:!1}))return a.responseText},parseStyles:function(a,b){for(var c=0,d=a.length;c<d;c++){var e=this.parseStyle(a[c]);e&&(this.styles[(b.styleBaseUrl||"")+"#"+e.id]=e)}},parseKmlColor:function(a){var b=
2424 null;a&&(a=a.match(this.regExes.kmlColor))&&(b={color:"#"+a[4]+a[3]+a[2],opacity:parseInt(a[1],16)/255});return b},parseStyle:function(a){for(var b={},c=["LineStyle","PolyStyle","IconStyle","BalloonStyle","LabelStyle"],d,e,f=0,g=c.length;f<g;++f)if(d=c[f],e=this.getElementsByTagNameNS(a,"*",d)[0])switch(d.toLowerCase()){case "linestyle":d=this.parseProperty(e,"*","color");if(d=this.parseKmlColor(d))b.strokeColor=d.color,b.strokeOpacity=d.opacity;(d=this.parseProperty(e,"*","width"))&&(b.strokeWidth=
2425 d);break;case "polystyle":d=this.parseProperty(e,"*","color");if(d=this.parseKmlColor(d))b.fillOpacity=d.opacity,b.fillColor=d.color;"0"==this.parseProperty(e,"*","fill")&&(b.fillColor="none");"0"==this.parseProperty(e,"*","outline")&&(b.strokeWidth="0");break;case "iconstyle":var h=parseFloat(this.parseProperty(e,"*","scale")||1);d=32*h;var i=32*h,j=this.getElementsByTagNameNS(e,"*","Icon")[0];if(j){var k=this.parseProperty(j,"*","href");if(k){var l=this.parseProperty(j,"*","w"),m=this.parseProperty(j,
2426 "*","h");OpenLayers.String.startsWith(k,"http://maps.google.com/mapfiles/kml")&&(!l&&!m)&&(m=l=64,h/=2);l=l||m;m=m||l;l&&(d=parseInt(l)*h);m&&(i=parseInt(m)*h);if(m=k.match(this.regExes.kmlIconPalette))l=m[1],m=m[2],k=this.parseProperty(j,"*","x"),j=this.parseProperty(j,"*","y"),k="http://maps.google.com/mapfiles/kml/pal"+l+"/icon"+(8*(j?7-j/32:7)+(k?k/32:0))+m;b.graphicOpacity=1;b.externalGraphic=k}}if(e=this.getElementsByTagNameNS(e,"*","hotSpot")[0])k=parseFloat(e.getAttribute("x")),j=parseFloat(e.getAttribute("y")),
2427 l=e.getAttribute("xunits"),"pixels"==l?b.graphicXOffset=-k*h:"insetPixels"==l?b.graphicXOffset=-d+k*h:"fraction"==l&&(b.graphicXOffset=-d*k),e=e.getAttribute("yunits"),"pixels"==e?b.graphicYOffset=-i+j*h+1:"insetPixels"==e?b.graphicYOffset=-(j*h)+1:"fraction"==e&&(b.graphicYOffset=-i*(1-j)+1);b.graphicWidth=d;b.graphicHeight=i;break;case "balloonstyle":(e=OpenLayers.Util.getXmlNodeValue(e))&&(b.balloonStyle=e.replace(this.regExes.straightBracket,"${$1}"));break;case "labelstyle":if(d=this.parseProperty(e,
2428 "*","color"),d=this.parseKmlColor(d))b.fontColor=d.color,b.fontOpacity=d.opacity}!b.strokeColor&&b.fillColor&&(b.strokeColor=b.fillColor);if((a=a.getAttribute("id"))&&b)b.id=a;return b},parseStyleMaps:function(a,b){for(var c=0,d=a.length;c<d;c++)for(var e=a[c],f=this.getElementsByTagNameNS(e,"*","Pair"),e=e.getAttribute("id"),g=0,h=f.length;g<h;g++){var i=f[g],j=this.parseProperty(i,"*","key");(i=this.parseProperty(i,"*","styleUrl"))&&"normal"==j&&(this.styles[(b.styleBaseUrl||"")+"#"+e]=this.styles[(b.styleBaseUrl||
2429 "")+i])}},parseFeatures:function(a,b){for(var c=[],d=0,e=a.length;d<e;d++){var f=a[d],g=this.parseFeature.apply(this,[f]);if(g){this.extractStyles&&(g.attributes&&g.attributes.styleUrl)&&(g.style=this.getStyle(g.attributes.styleUrl,b));if(this.extractStyles){var h=this.getElementsByTagNameNS(f,"*","Style")[0];if(h&&(h=this.parseStyle(h)))g.style=OpenLayers.Util.extend(g.style,h)}if(this.extractTracks){if((f=this.getElementsByTagNameNS(f,this.namespaces.gx,"Track"))&&0<f.length)g={features:[],feature:g},
2430 this.readNode(f[0],g),0<g.features.length&&c.push.apply(c,g.features)}else c.push(g)}else throw"Bad Placemark: "+d;}this.features=this.features.concat(c)},readers:{kml:{when:function(a,b){b.whens.push(OpenLayers.Date.parse(this.getChildValue(a)))},_trackPointAttribute:function(a,b){var c=a.nodeName.split(":").pop();b.attributes[c].push(this.getChildValue(a))}},gx:{Track:function(a,b){var c={whens:[],points:[],angles:[]};if(this.trackAttributes){var d;c.attributes={};for(var e=0,f=this.trackAttributes.length;e<
2431 f;++e)d=this.trackAttributes[e],c.attributes[d]=[],d in this.readers.kml||(this.readers.kml[d]=this.readers.kml._trackPointAttribute)}this.readChildNodes(a,c);if(c.whens.length!==c.points.length)throw Error("gx:Track with unequal number of when ("+c.whens.length+") and gx:coord ("+c.points.length+") elements.");var g=0<c.angles.length;if(g&&c.whens.length!==c.angles.length)throw Error("gx:Track with unequal number of when ("+c.whens.length+") and gx:angles ("+c.angles.length+") elements.");for(var h,
2432 i,e=0,f=c.whens.length;e<f;++e){h=b.feature.clone();h.fid=b.feature.fid||b.feature.id;i=c.points[e];h.geometry=i;"z"in i&&(h.attributes.altitude=i.z);this.internalProjection&&this.externalProjection&&h.geometry.transform(this.externalProjection,this.internalProjection);if(this.trackAttributes){i=0;for(var j=this.trackAttributes.length;i<j;++i)h.attributes[d]=c.attributes[this.trackAttributes[i]][e]}h.attributes.when=c.whens[e];h.attributes.trackId=b.feature.id;g&&(i=c.angles[e],h.attributes.heading=
2433 parseFloat(i[0]),h.attributes.tilt=parseFloat(i[1]),h.attributes.roll=parseFloat(i[2]));b.features.push(h)}},coord:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(/\s+/),d=new OpenLayers.Geometry.Point(c[0],c[1]);2<c.length&&(d.z=parseFloat(c[2]));b.points.push(d)},angles:function(a,b){var c=this.getChildValue(a).replace(this.regExes.trimSpace,"").split(/\s+/);b.angles.push(c)}}},parseFeature:function(a){for(var b=["MultiGeometry","Polygon","LineString","Point"],
2434 c,d,e,f=0,g=b.length;f<g;++f)if(c=b[f],this.internalns=a.namespaceURI?a.namespaceURI:this.kmlns,d=this.getElementsByTagNameNS(a,this.internalns,c),0<d.length){if(b=this.parseGeometry[c.toLowerCase()])e=b.apply(this,[d[0]]),this.internalProjection&&this.externalProjection&&e.transform(this.externalProjection,this.internalProjection);else throw new TypeError("Unsupported geometry type: "+c);break}var h;this.extractAttributes&&(h=this.parseAttributes(a));c=new OpenLayers.Feature.Vector(e,h);a=a.getAttribute("id")||
2435 a.getAttribute("name");null!=a&&(c.fid=a);return c},getStyle:function(a,b){var c=OpenLayers.Util.removeTail(a),d=OpenLayers.Util.extend({},b);d.depth++;d.styleBaseUrl=c;!this.styles[a]&&!OpenLayers.String.startsWith(a,"#")&&d.depth<=this.maxDepth&&!this.fetched[c]&&(c=this.fetchLink(c))&&this.parseData(c,d);return OpenLayers.Util.extend({},this.styles[a])},parseGeometry:{point:function(a){var b=this.getElementsByTagNameNS(a,this.internalns,"coordinates"),a=[];if(0<b.length)var c=b[0].firstChild.nodeValue,
2436 c=c.replace(this.regExes.removeSpace,""),a=c.split(",");b=null;if(1<a.length)2==a.length&&(a[2]=null),b=new OpenLayers.Geometry.Point(a[0],a[1],a[2]);else throw"Bad coordinate string: "+c;return b},linestring:function(a,b){var c=this.getElementsByTagNameNS(a,this.internalns,"coordinates"),d=null;if(0<c.length){for(var c=this.getChildValue(c[0]),c=c.replace(this.regExes.trimSpace,""),c=c.replace(this.regExes.trimComma,","),d=c.split(this.regExes.splitSpace),e=d.length,f=Array(e),g,h,i=0;i<e;++i)if(g=
2437 d[i].split(","),h=g.length,1<h)2==g.length&&(g[2]=null),f[i]=new OpenLayers.Geometry.Point(g[0],g[1],g[2]);else throw"Bad LineString point coordinates: "+d[i];if(e)d=b?new OpenLayers.Geometry.LinearRing(f):new OpenLayers.Geometry.LineString(f);else throw"Bad LineString coordinates: "+c;}return d},polygon:function(a){var a=this.getElementsByTagNameNS(a,this.internalns,"LinearRing"),b=a.length,c=Array(b);if(0<b)for(var d=0,e=a.length;d<e;++d)if(b=this.parseGeometry.linestring.apply(this,[a[d],!0]))c[d]=
2438 b;else throw"Bad LinearRing geometry: "+d;return new OpenLayers.Geometry.Polygon(c)},multigeometry:function(a){for(var b,c=[],d=a.childNodes,e=0,f=d.length;e<f;++e)a=d[e],1==a.nodeType&&(b=this.parseGeometry[(a.prefix?a.nodeName.split(":")[1]:a.nodeName).toLowerCase()])&&c.push(b.apply(this,[a]));return new OpenLayers.Geometry.Collection(c)}},parseAttributes:function(a){var b={},c=a.getElementsByTagName("ExtendedData");c.length&&(b=this.parseExtendedData(c[0]));for(var d,e,f,a=a.childNodes,c=0,g=
2439 a.length;c<g;++c)if(d=a[c],1==d.nodeType&&(e=d.childNodes,1<=e.length&&3>=e.length)){switch(e.length){case 1:f=e[0];break;case 2:f=e[0];e=e[1];f=3==f.nodeType||4==f.nodeType?f:e;break;default:f=e[1]}if(3==f.nodeType||4==f.nodeType)if(d=d.prefix?d.nodeName.split(":")[1]:d.nodeName,f=OpenLayers.Util.getXmlNodeValue(f))f=f.replace(this.regExes.trimSpace,""),b[d]=f}return b},parseExtendedData:function(a){var b={},c,d,e,f,g=a.getElementsByTagName("Data");c=0;for(d=g.length;c<d;c++){e=g[c];f=e.getAttribute("name");
2440 var h={},i=e.getElementsByTagName("value");i.length&&(h.value=this.getChildValue(i[0]));this.kvpAttributes?b[f]=h.value:(e=e.getElementsByTagName("displayName"),e.length&&(h.displayName=this.getChildValue(e[0])),b[f]=h)}a=a.getElementsByTagName("SimpleData");c=0;for(d=a.length;c<d;c++)h={},e=a[c],f=e.getAttribute("name"),h.value=this.getChildValue(e),this.kvpAttributes?b[f]=h.value:(h.displayName=f,b[f]=h);return b},parseProperty:function(a,b,c){var d,a=this.getElementsByTagNameNS(a,b,c);try{d=OpenLayers.Util.getXmlNodeValue(a[0])}catch(e){d=
2441 null}return d},write:function(a){OpenLayers.Util.isArray(a)||(a=[a]);for(var b=this.createElementNS(this.kmlns,"kml"),c=this.createFolderXML(),d=0,e=a.length;d<e;++d)c.appendChild(this.createPlacemarkXML(a[d]));b.appendChild(c);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFolderXML:function(){var a=this.createElementNS(this.kmlns,"Folder");if(this.foldersName){var b=this.createElementNS(this.kmlns,"name"),c=this.createTextNode(this.foldersName);b.appendChild(c);a.appendChild(b)}this.foldersDesc&&
2442 (b=this.createElementNS(this.kmlns,"description"),c=this.createTextNode(this.foldersDesc),b.appendChild(c),a.appendChild(b));return a},createPlacemarkXML:function(a){var b=this.createElementNS(this.kmlns,"name");b.appendChild(this.createTextNode(a.style&&a.style.label?a.style.label:a.attributes.name||a.id));var c=this.createElementNS(this.kmlns,"description");c.appendChild(this.createTextNode(a.attributes.description||this.placemarksDesc));var d=this.createElementNS(this.kmlns,"Placemark");null!=
2443 a.fid&&d.setAttribute("id",a.fid);d.appendChild(b);d.appendChild(c);b=this.buildGeometryNode(a.geometry);d.appendChild(b);a.attributes&&(a=this.buildExtendedData(a.attributes))&&d.appendChild(a);return d},buildGeometryNode:function(a){var b=a.CLASS_NAME,b=this.buildGeometry[b.substring(b.lastIndexOf(".")+1).toLowerCase()],c=null;b&&(c=b.apply(this,[a]));return c},buildGeometry:{point:function(a){var b=this.createElementNS(this.kmlns,"Point");b.appendChild(this.buildCoordinatesNode(a));return b},multipoint:function(a){return this.buildGeometry.collection.apply(this,
2444 [a])},linestring:function(a){var b=this.createElementNS(this.kmlns,"LineString");b.appendChild(this.buildCoordinatesNode(a));return b},multilinestring:function(a){return this.buildGeometry.collection.apply(this,[a])},linearring:function(a){var b=this.createElementNS(this.kmlns,"LinearRing");b.appendChild(this.buildCoordinatesNode(a));return b},polygon:function(a){for(var b=this.createElementNS(this.kmlns,"Polygon"),a=a.components,c,d,e=0,f=a.length;e<f;++e)c=0==e?"outerBoundaryIs":"innerBoundaryIs",
2445 c=this.createElementNS(this.kmlns,c),d=this.buildGeometry.linearring.apply(this,[a[e]]),c.appendChild(d),b.appendChild(c);return b},multipolygon:function(a){return this.buildGeometry.collection.apply(this,[a])},collection:function(a){for(var b=this.createElementNS(this.kmlns,"MultiGeometry"),c,d=0,e=a.components.length;d<e;++d)(c=this.buildGeometryNode.apply(this,[a.components[d]]))&&b.appendChild(c);return b}},buildCoordinatesNode:function(a){var b=this.createElementNS(this.kmlns,"coordinates"),
2446 c;if(c=a.components){for(var d=c.length,e=Array(d),f=0;f<d;++f)a=c[f],e[f]=this.buildCoordinates(a);c=e.join(" ")}else c=this.buildCoordinates(a);c=this.createTextNode(c);b.appendChild(c);return b},buildCoordinates:function(a){this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));return a.x+","+a.y},buildExtendedData:function(a){var b=this.createElementNS(this.kmlns,"ExtendedData"),c;for(c in a)if(a[c]&&"name"!=c&&"description"!=
2447 c&&"styleUrl"!=c){var d=this.createElementNS(this.kmlns,"Data");d.setAttribute("name",c);var e=this.createElementNS(this.kmlns,"value");if("object"==typeof a[c]){if(a[c].value&&e.appendChild(this.createTextNode(a[c].value)),a[c].displayName){var f=this.createElementNS(this.kmlns,"displayName");f.appendChild(this.getXMLDoc().createCDATASection(a[c].displayName));d.appendChild(f)}}else e.appendChild(this.createTextNode(a[c]));d.appendChild(e);b.appendChild(d)}return this.isSimpleContent(b)?null:b},
2448 CLASS_NAME:"OpenLayers.Format.KML"});OpenLayers.Popup=OpenLayers.Class({events:null,id:"",lonlat:null,div:null,contentSize:null,size:null,contentHTML:null,backgroundColor:"",opacity:"",border:"",contentDiv:null,groupDiv:null,closeDiv:null,autoSize:!1,minSize:null,maxSize:null,displayClass:"olPopup",contentDisplayClass:"olPopupContent",padding:0,disableFirefoxOverflowHack:!1,fixPadding:function(){"number"==typeof this.padding&&(this.padding=new OpenLayers.Bounds(this.padding,this.padding,this.padding,this.padding))},panMapIfOutOfView:!1,
2449 keepInMap:!1,closeOnMove:!1,map:null,initialize:function(a,b,c,d,e,f){null==a&&(a=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_"));this.id=a;this.lonlat=b;this.contentSize=null!=c?c:new OpenLayers.Size(OpenLayers.Popup.WIDTH,OpenLayers.Popup.HEIGHT);null!=d&&(this.contentHTML=d);this.backgroundColor=OpenLayers.Popup.COLOR;this.opacity=OpenLayers.Popup.OPACITY;this.border=OpenLayers.Popup.BORDER;this.div=OpenLayers.Util.createDiv(this.id,null,null,null,null,null,"hidden");this.div.className=this.displayClass;
2450 this.groupDiv=OpenLayers.Util.createDiv(this.id+"_GroupDiv",null,null,null,"relative",null,"hidden");a=this.div.id+"_contentDiv";this.contentDiv=OpenLayers.Util.createDiv(a,null,this.contentSize.clone(),null,"relative");this.contentDiv.className=this.contentDisplayClass;this.groupDiv.appendChild(this.contentDiv);this.div.appendChild(this.groupDiv);e&&this.addCloseBox(f);this.registerEvents()},destroy:function(){this.border=this.opacity=this.backgroundColor=this.contentHTML=this.size=this.lonlat=this.id=
2451 null;this.closeOnMove&&this.map&&this.map.events.unregister("movestart",this,this.hide);this.events.destroy();this.events=null;this.closeDiv&&(OpenLayers.Event.stopObservingElement(this.closeDiv),this.groupDiv.removeChild(this.closeDiv));this.closeDiv=null;this.div.removeChild(this.groupDiv);this.groupDiv=null;null!=this.map&&this.map.removePopup(this);this.panMapIfOutOfView=this.padding=this.maxSize=this.minSize=this.autoSize=this.div=this.map=null},draw:function(a){null==a&&null!=this.lonlat&&null!=
2452 this.map&&(a=this.map.getLayerPxFromLonLat(this.lonlat));this.closeOnMove&&this.map.events.register("movestart",this,this.hide);!this.disableFirefoxOverflowHack&&"firefox"==OpenLayers.BROWSER_NAME&&(this.map.events.register("movestart",this,function(){var a=document.defaultView.getComputedStyle(this.contentDiv,null).getPropertyValue("overflow");"hidden"!=a&&(this.contentDiv._oldOverflow=a,this.contentDiv.style.overflow="hidden")}),this.map.events.register("moveend",this,function(){var a=this.contentDiv._oldOverflow;
2453 a&&(this.contentDiv.style.overflow=a,this.contentDiv._oldOverflow=null)}));this.moveTo(a);!this.autoSize&&!this.size&&this.setSize(this.contentSize);this.setBackgroundColor();this.setOpacity();this.setBorder();this.setContentHTML();this.panMapIfOutOfView&&this.panIntoView();return this.div},updatePosition:function(){if(this.lonlat&&this.map){var a=this.map.getLayerPxFromLonLat(this.lonlat);a&&this.moveTo(a)}},moveTo:function(a){null!=a&&null!=this.div&&(this.div.style.left=a.x+"px",this.div.style.top=
2454 a.y+"px")},visible:function(){return OpenLayers.Element.visible(this.div)},toggle:function(){this.visible()?this.hide():this.show()},show:function(){this.div.style.display="";this.panMapIfOutOfView&&this.panIntoView()},hide:function(){this.div.style.display="none"},setSize:function(a){this.size=a.clone();var b=this.getContentDivPadding(),c=b.left+b.right,d=b.top+b.bottom;this.fixPadding();c+=this.padding.left+this.padding.right;d+=this.padding.top+this.padding.bottom;if(this.closeDiv)var e=parseInt(this.closeDiv.style.width),
2455 c=c+(e+b.right);this.size.w+=c;this.size.h+=d;"msie"==OpenLayers.BROWSER_NAME&&(this.contentSize.w+=b.left+b.right,this.contentSize.h+=b.bottom+b.top);null!=this.div&&(this.div.style.width=this.size.w+"px",this.div.style.height=this.size.h+"px");null!=this.contentDiv&&(this.contentDiv.style.width=a.w+"px",this.contentDiv.style.height=a.h+"px")},updateSize:function(){var a="<div class='"+this.contentDisplayClass+"'>"+this.contentDiv.innerHTML+"</div>",b=this.map?this.map.div:document.body,c=OpenLayers.Util.getRenderedDimensions(a,
2456 null,{displayClass:this.displayClass,containerElement:b}),d=this.getSafeContentSize(c),e=null;d.equals(c)?e=c:(c={w:d.w<c.w?d.w:null,h:d.h<c.h?d.h:null},c.w&&c.h?e=d:(a=OpenLayers.Util.getRenderedDimensions(a,c,{displayClass:this.contentDisplayClass,containerElement:b}),"hidden"!=OpenLayers.Element.getStyle(this.contentDiv,"overflow")&&a.equals(d)&&(d=OpenLayers.Util.getScrollbarWidth(),c.w?a.h+=d:a.w+=d),e=this.getSafeContentSize(a)));this.setSize(e)},setBackgroundColor:function(a){void 0!=a&&(this.backgroundColor=
2457 a);null!=this.div&&(this.div.style.backgroundColor=this.backgroundColor)},setOpacity:function(a){void 0!=a&&(this.opacity=a);null!=this.div&&(this.div.style.opacity=this.opacity,this.div.style.filter="alpha(opacity="+100*this.opacity+")")},setBorder:function(a){void 0!=a&&(this.border=a);null!=this.div&&(this.div.style.border=this.border)},setContentHTML:function(a){null!=a&&(this.contentHTML=a);null!=this.contentDiv&&(null!=this.contentHTML&&this.contentHTML!=this.contentDiv.innerHTML)&&(this.contentDiv.innerHTML=
2458 this.contentHTML,this.autoSize&&(this.registerImageListeners(),this.updateSize()))},registerImageListeners:function(){for(var a=function(){null!==this.popup.id&&(this.popup.updateSize(),this.popup.visible()&&this.popup.panMapIfOutOfView&&this.popup.panIntoView(),OpenLayers.Event.stopObserving(this.img,"load",this.img._onImageLoad))},b=this.contentDiv.getElementsByTagName("img"),c=0,d=b.length;c<d;c++){var e=b[c];if(0==e.width||0==e.height)e._onImgLoad=OpenLayers.Function.bind(a,{popup:this,img:e}),
2459 OpenLayers.Event.observe(e,"load",e._onImgLoad)}},getSafeContentSize:function(a){var a=a.clone(),b=this.getContentDivPadding(),c=b.left+b.right,d=b.top+b.bottom;this.fixPadding();c+=this.padding.left+this.padding.right;d+=this.padding.top+this.padding.bottom;if(this.closeDiv)var e=parseInt(this.closeDiv.style.width),c=c+(e+b.right);this.minSize&&(a.w=Math.max(a.w,this.minSize.w-c),a.h=Math.max(a.h,this.minSize.h-d));this.maxSize&&(a.w=Math.min(a.w,this.maxSize.w-c),a.h=Math.min(a.h,this.maxSize.h-
2460 d));if(this.map&&this.map.size){e=b=0;if(this.keepInMap&&!this.panMapIfOutOfView)switch(e=this.map.getPixelFromLonLat(this.lonlat),this.relativePosition){case "tr":b=e.x;e=this.map.size.h-e.y;break;case "tl":b=this.map.size.w-e.x;e=this.map.size.h-e.y;break;case "bl":b=this.map.size.w-e.x;e=e.y;break;case "br":b=e.x;e=e.y;break;default:b=e.x,e=this.map.size.h-e.y}d=this.map.size.h-this.map.paddingForPopups.top-this.map.paddingForPopups.bottom-d-e;a.w=Math.min(a.w,this.map.size.w-this.map.paddingForPopups.left-
2461 this.map.paddingForPopups.right-c-b);a.h=Math.min(a.h,d)}return a},getContentDivPadding:function(){var a=this._contentDivPadding;if(!a&&(null==this.div.parentNode&&(this.div.style.display="none",document.body.appendChild(this.div)),this._contentDivPadding=a=new OpenLayers.Bounds(OpenLayers.Element.getStyle(this.contentDiv,"padding-left"),OpenLayers.Element.getStyle(this.contentDiv,"padding-bottom"),OpenLayers.Element.getStyle(this.contentDiv,"padding-right"),OpenLayers.Element.getStyle(this.contentDiv,
2462 "padding-top")),this.div.parentNode==document.body))document.body.removeChild(this.div),this.div.style.display="";return a},addCloseBox:function(a){this.closeDiv=OpenLayers.Util.createDiv(this.id+"_close",null,{w:17,h:17});this.closeDiv.className="olPopupCloseBox";var b=this.getContentDivPadding();this.closeDiv.style.right=b.right+"px";this.closeDiv.style.top=b.top+"px";this.groupDiv.appendChild(this.closeDiv);a=a||function(a){this.hide();OpenLayers.Event.stop(a)};OpenLayers.Event.observe(this.closeDiv,
2463 "touchend",OpenLayers.Function.bindAsEventListener(a,this));OpenLayers.Event.observe(this.closeDiv,"click",OpenLayers.Function.bindAsEventListener(a,this))},panIntoView:function(){var a=this.map.getSize(),b=this.map.getViewPortPxFromLayerPx(new OpenLayers.Pixel(parseInt(this.div.style.left),parseInt(this.div.style.top))),c=b.clone();b.x<this.map.paddingForPopups.left?c.x=this.map.paddingForPopups.left:b.x+this.size.w>a.w-this.map.paddingForPopups.right&&(c.x=a.w-this.map.paddingForPopups.right-this.size.w);
2464 b.y<this.map.paddingForPopups.top?c.y=this.map.paddingForPopups.top:b.y+this.size.h>a.h-this.map.paddingForPopups.bottom&&(c.y=a.h-this.map.paddingForPopups.bottom-this.size.h);this.map.pan(b.x-c.x,b.y-c.y)},registerEvents:function(){this.events=new OpenLayers.Events(this,this.div,null,!0);this.events.on({mousedown:this.onmousedown,mousemove:this.onmousemove,mouseup:this.onmouseup,click:this.onclick,mouseout:this.onmouseout,dblclick:this.ondblclick,touchstart:function(a){OpenLayers.Event.stop(a,!0)},
2465 scope:this})},onmousedown:function(a){this.mousedown=!0;OpenLayers.Event.stop(a,!0)},onmousemove:function(a){this.mousedown&&OpenLayers.Event.stop(a,!0)},onmouseup:function(a){this.mousedown&&(this.mousedown=!1,OpenLayers.Event.stop(a,!0))},onclick:function(a){OpenLayers.Event.stop(a,!0)},onmouseout:function(){this.mousedown=!1},ondblclick:function(a){OpenLayers.Event.stop(a,!0)},CLASS_NAME:"OpenLayers.Popup"});OpenLayers.Popup.WIDTH=200;OpenLayers.Popup.HEIGHT=200;OpenLayers.Popup.COLOR="white";
2466 OpenLayers.Popup.OPACITY=1;OpenLayers.Popup.BORDER="0px";OpenLayers.Popup.Anchored=OpenLayers.Class(OpenLayers.Popup,{relativePosition:null,keepInMap:!0,anchor:null,initialize:function(a,b,c,d,e,f,g){OpenLayers.Popup.prototype.initialize.apply(this,[a,b,c,d,f,g]);this.anchor=null!=e?e:{size:new OpenLayers.Size(0,0),offset:new OpenLayers.Pixel(0,0)}},destroy:function(){this.relativePosition=this.anchor=null;OpenLayers.Popup.prototype.destroy.apply(this,arguments)},show:function(){this.updatePosition();OpenLayers.Popup.prototype.show.apply(this,arguments)},
2467 moveTo:function(a){var b=this.relativePosition;this.relativePosition=this.calculateRelativePosition(a);a=this.calculateNewPx(a);OpenLayers.Popup.prototype.moveTo.apply(this,Array(a));this.relativePosition!=b&&this.updateRelativePosition()},setSize:function(a){OpenLayers.Popup.prototype.setSize.apply(this,arguments);this.lonlat&&this.map&&this.moveTo(this.map.getLayerPxFromLonLat(this.lonlat))},calculateRelativePosition:function(a){a=this.map.getLonLatFromLayerPx(a);a=this.map.getExtent().determineQuadrant(a);
2468 return OpenLayers.Bounds.oppositeQuadrant(a)},updateRelativePosition:function(){},calculateNewPx:function(a){var a=a.offset(this.anchor.offset),b=this.size||this.contentSize,c="t"==this.relativePosition.charAt(0);a.y+=c?-b.h:this.anchor.size.h;c="l"==this.relativePosition.charAt(1);a.x+=c?-b.w:this.anchor.size.w;return a},CLASS_NAME:"OpenLayers.Popup.Anchored"});/*
2469 Apache 2
2470
2471 Contains portions of Rico <http://openrico.org/>
2472
2473 Copyright 2005 Sabre Airline Solutions
2474
2475 Licensed under the Apache License, Version 2.0 (the "License"); you
2476 may not use this file except in compliance with the License. You
2477 may obtain a copy of the License at
2478
2479 http://www.apache.org/licenses/LICENSE-2.0
2480
2481 Unless required by applicable law or agreed to in writing, software
2482 distributed under the License is distributed on an "AS IS" BASIS,
2483 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
2484 implied. See the License for the specific language governing
2485 permissions and limitations under the License.
2486 */
2487 OpenLayers.Console.warn("OpenLayers.Rico is deprecated");OpenLayers.Rico=OpenLayers.Rico||{};
2488 OpenLayers.Rico.Color=OpenLayers.Class({initialize:function(a,b,c){this.rgb={r:a,g:b,b:c}},setRed:function(a){this.rgb.r=a},setGreen:function(a){this.rgb.g=a},setBlue:function(a){this.rgb.b=a},setHue:function(a){var b=this.asHSB();b.h=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setSaturation:function(a){var b=this.asHSB();b.s=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},setBrightness:function(a){var b=this.asHSB();b.b=a;this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,b.b)},
2489 darken:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.max(b.b-a,0))},brighten:function(a){var b=this.asHSB();this.rgb=OpenLayers.Rico.Color.HSBtoRGB(b.h,b.s,Math.min(b.b+a,1))},blend:function(a){this.rgb.r=Math.floor((this.rgb.r+a.rgb.r)/2);this.rgb.g=Math.floor((this.rgb.g+a.rgb.g)/2);this.rgb.b=Math.floor((this.rgb.b+a.rgb.b)/2)},isBright:function(){this.asHSB();return 0.5<this.asHSB().b},isDark:function(){return!this.isBright()},asRGB:function(){return"rgb("+
2490 this.rgb.r+","+this.rgb.g+","+this.rgb.b+")"},asHex:function(){return"#"+this.rgb.r.toColorPart()+this.rgb.g.toColorPart()+this.rgb.b.toColorPart()},asHSB:function(){return OpenLayers.Rico.Color.RGBtoHSB(this.rgb.r,this.rgb.g,this.rgb.b)},toString:function(){return this.asHex()}});
2491 OpenLayers.Rico.Color.createFromHex=function(a){if(4==a.length)for(var b=a,a="#",c=1;4>c;c++)a+=b.charAt(c)+b.charAt(c);0==a.indexOf("#")&&(a=a.substring(1));b=a.substring(0,2);c=a.substring(2,4);a=a.substring(4,6);return new OpenLayers.Rico.Color(parseInt(b,16),parseInt(c,16),parseInt(a,16))};
2492 OpenLayers.Rico.Color.createColorFromBackground=function(a){var b=OpenLayers.Element.getStyle(OpenLayers.Util.getElement(a),"backgroundColor");return"transparent"==b&&a.parentNode?OpenLayers.Rico.Color.createColorFromBackground(a.parentNode):null==b?new OpenLayers.Rico.Color(255,255,255):0==b.indexOf("rgb(")?(a=b.substring(4,b.length-1).split(","),new OpenLayers.Rico.Color(parseInt(a[0]),parseInt(a[1]),parseInt(a[2]))):0==b.indexOf("#")?OpenLayers.Rico.Color.createFromHex(b):new OpenLayers.Rico.Color(255,
2493 255,255)};
2494 OpenLayers.Rico.Color.HSBtoRGB=function(a,b,c){var d=0,e=0,f=0;if(0==b)f=e=d=parseInt(255*c+0.5);else{var a=6*(a-Math.floor(a)),g=a-Math.floor(a),h=c*(1-b),i=c*(1-b*g),b=c*(1-b*(1-g));switch(parseInt(a)){case 0:d=255*c+0.5;e=255*b+0.5;f=255*h+0.5;break;case 1:d=255*i+0.5;e=255*c+0.5;f=255*h+0.5;break;case 2:d=255*h+0.5;e=255*c+0.5;f=255*b+0.5;break;case 3:d=255*h+0.5;e=255*i+0.5;f=255*c+0.5;break;case 4:d=255*b+0.5;e=255*h+0.5;f=255*c+0.5;break;case 5:d=255*c+0.5,e=255*h+0.5,f=255*i+0.5}}return{r:parseInt(d),g:parseInt(e),
2495 b:parseInt(f)}};OpenLayers.Rico.Color.RGBtoHSB=function(a,b,c){var d,e=a>b?a:b;c>e&&(e=c);var f=a<b?a:b;c<f&&(f=c);d=0!=e?(e-f)/e:0;if(0==d)a=0;else{var g=(e-a)/(e-f),h=(e-b)/(e-f),c=(e-c)/(e-f),a=(a==e?c-h:b==e?2+g-c:4+h-g)/6;0>a&&(a+=1)}return{h:a,s:d,b:e/255}};OpenLayers.Console.warn("OpenLayers.Rico is deprecated");OpenLayers.Rico=OpenLayers.Rico||{};
2496 OpenLayers.Rico.Corner={round:function(a,b){a=OpenLayers.Util.getElement(a);this._setOptions(b);var c=this.options.color;"fromElement"==this.options.color&&(c=this._background(a));var d=this.options.bgColor;"fromParent"==this.options.bgColor&&(d=this._background(a.offsetParent));this._roundCornersImpl(a,c,d)},changeColor:function(a,b){a.style.backgroundColor=b;for(var c=a.parentNode.getElementsByTagName("span"),d=0;d<c.length;d++)c[d].style.backgroundColor=b},changeOpacity:function(a,b){var c="alpha(opacity="+
2497 100*b+")";a.style.opacity=b;a.style.filter=c;for(var d=a.parentNode.getElementsByTagName("span"),e=0;e<d.length;e++)d[e].style.opacity=b,d[e].style.filter=c},reRound:function(a,b){var c=a.parentNode.childNodes[2];a.parentNode.removeChild(a.parentNode.childNodes[0]);a.parentNode.removeChild(c);this.round(a.parentNode,b)},_roundCornersImpl:function(a,b,c){this.options.border&&this._renderBorder(a,c);this._isTopRounded()&&this._roundTopCorners(a,b,c);this._isBottomRounded()&&this._roundBottomCorners(a,
2498 b,c)},_renderBorder:function(a,b){var c="1px solid "+this._borderColor(b);a.innerHTML="<div "+("style='border-left: "+c+";"+("border-right: "+c)+"'")+">"+a.innerHTML+"</div>"},_roundTopCorners:function(a,b,c){for(var d=this._createCorner(c),e=0;e<this.options.numSlices;e++)d.appendChild(this._createCornerSlice(b,c,e,"top"));a.style.paddingTop=0;a.insertBefore(d,a.firstChild)},_roundBottomCorners:function(a,b,c){for(var d=this._createCorner(c),e=this.options.numSlices-1;0<=e;e--)d.appendChild(this._createCornerSlice(b,
2499 c,e,"bottom"));a.style.paddingBottom=0;a.appendChild(d)},_createCorner:function(a){var b=document.createElement("div");b.style.backgroundColor=this._isTransparent()?"transparent":a;return b},_createCornerSlice:function(a,b,c,d){var e=document.createElement("span"),f=e.style;f.backgroundColor=a;f.display="block";f.height="1px";f.overflow="hidden";f.fontSize="1px";a=this._borderColor(a,b);this.options.border&&0==c?(f.borderTopStyle="solid",f.borderTopWidth="1px",f.borderLeftWidth="0px",f.borderRightWidth=
2500 "0px",f.borderBottomWidth="0px",f.height="0px",f.borderColor=a):a&&(f.borderColor=a,f.borderStyle="solid",f.borderWidth="0px 1px");!this.options.compact&&c==this.options.numSlices-1&&(f.height="2px");this._setMargin(e,c,d);this._setBorder(e,c,d);return e},_setOptions:function(a){this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:!0,border:!1,compact:!1};OpenLayers.Util.extend(this.options,a||{});this.options.numSlices=this.options.compact?2:4;this._isTransparent()&&(this.options.blend=
2501 !1)},_whichSideTop:function(){return this._hasString(this.options.corners,"all","top")||0<=this.options.corners.indexOf("tl")&&0<=this.options.corners.indexOf("tr")?"":0<=this.options.corners.indexOf("tl")?"left":0<=this.options.corners.indexOf("tr")?"right":""},_whichSideBottom:function(){return this._hasString(this.options.corners,"all","bottom")||0<=this.options.corners.indexOf("bl")&&0<=this.options.corners.indexOf("br")?"":0<=this.options.corners.indexOf("bl")?"left":0<=this.options.corners.indexOf("br")?
2502 "right":""},_borderColor:function(a,b){return"transparent"==a?b:this.options.border?this.options.border:this.options.blend?this._blend(b,a):""},_setMargin:function(a,b,c){b=this._marginSize(b);c="top"==c?this._whichSideTop():this._whichSideBottom();"left"==c?(a.style.marginLeft=b+"px",a.style.marginRight="0px"):"right"==c?(a.style.marginRight=b+"px",a.style.marginLeft="0px"):(a.style.marginLeft=b+"px",a.style.marginRight=b+"px")},_setBorder:function(a,b,c){b=this._borderSize(b);c="top"==c?this._whichSideTop():
2503 this._whichSideBottom();"left"==c?(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth="0px"):"right"==c?(a.style.borderRightWidth=b+"px",a.style.borderLeftWidth="0px"):(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px");!1!=this.options.border&&(a.style.borderLeftWidth=b+"px",a.style.borderRightWidth=b+"px")},_marginSize:function(a){if(this._isTransparent())return 0;var b=[5,3,2,1],c=[3,2,1,0],d=[2,1],e=[1,0];return this.options.compact&&this.options.blend?e[a]:this.options.compact?
2504 d[a]:this.options.blend?c[a]:b[a]},_borderSize:function(a){var b=[5,3,2,1],c=[2,1,1,1],d=[1,0],e=[0,2,0,0];return this.options.compact&&(this.options.blend||this._isTransparent())?1:this.options.compact?d[a]:this.options.blend?c[a]:this.options.border?e[a]:this._isTransparent()?b[a]:0},_hasString:function(a){for(var b=1;b<arguments.length;b++)if(0<=a.indexOf(arguments[b]))return!0;return!1},_blend:function(a,b){var c=OpenLayers.Rico.Color.createFromHex(a);c.blend(OpenLayers.Rico.Color.createFromHex(b));
2505 return c},_background:function(a){try{return OpenLayers.Rico.Color.createColorFromBackground(a).asHex()}catch(b){return"#ffffff"}},_isTransparent:function(){return"transparent"==this.options.color},_isTopRounded:function(){return this._hasString(this.options.corners,"all","top","tl","tr")},_isBottomRounded:function(){return this._hasString(this.options.corners,"all","bottom","bl","br")},_hasSingleTextChild:function(a){return 1==a.childNodes.length&&3==a.childNodes[0].nodeType}};OpenLayers.Popup.AnchoredBubble=OpenLayers.Class(OpenLayers.Popup.Anchored,{rounded:!1,initialize:function(a,b,c,d,e,f,g){OpenLayers.Console.warn("AnchoredBubble is deprecated");this.padding=new OpenLayers.Bounds(0,OpenLayers.Popup.AnchoredBubble.CORNER_SIZE,0,OpenLayers.Popup.AnchoredBubble.CORNER_SIZE);OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments)},draw:function(a){OpenLayers.Popup.Anchored.prototype.draw.apply(this,arguments);this.setContentHTML();this.setBackgroundColor();
2506 this.setOpacity();return this.div},updateRelativePosition:function(){this.setRicoCorners()},setSize:function(a){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.setRicoCorners()},setBackgroundColor:function(a){void 0!=a&&(this.backgroundColor=a);null!=this.div&&null!=this.contentDiv&&(this.div.style.background="transparent",OpenLayers.Rico.Corner.changeColor(this.groupDiv,this.backgroundColor))},setOpacity:function(a){OpenLayers.Popup.Anchored.prototype.setOpacity.call(this,
2507 a);null!=this.div&&null!=this.groupDiv&&OpenLayers.Rico.Corner.changeOpacity(this.groupDiv,this.opacity)},setBorder:function(){this.border=0},setRicoCorners:function(){var a={corners:this.getCornersToRound(this.relativePosition),color:this.backgroundColor,bgColor:"transparent",blend:!1};this.rounded?(OpenLayers.Rico.Corner.reRound(this.groupDiv,a),this.setBackgroundColor(),this.setOpacity()):(OpenLayers.Rico.Corner.round(this.div,a),this.rounded=!0)},getCornersToRound:function(){var a=["tl","tr",
2508 "bl","br"],b=OpenLayers.Bounds.oppositeQuadrant(this.relativePosition);OpenLayers.Util.removeItem(a,b);return a.join(" ")},CLASS_NAME:"OpenLayers.Popup.AnchoredBubble"});OpenLayers.Popup.AnchoredBubble.CORNER_SIZE=5;OpenLayers.Protocol.WFS.v1=OpenLayers.Class(OpenLayers.Protocol,{version:null,srsName:"EPSG:4326",featureType:null,featureNS:null,geometryName:"the_geom",schema:null,featurePrefix:"feature",formatOptions:null,readFormat:null,readOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=OpenLayers.Format.WFST(OpenLayers.Util.extend({version:this.version,featureType:this.featureType,featureNS:this.featureNS,featurePrefix:this.featurePrefix,geometryName:this.geometryName,
2509 srsName:this.srsName,schema:this.schema},this.formatOptions)));!a.geometryName&&1<parseFloat(this.format.version)&&this.setGeometryName(null)},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),
2510 c=OpenLayers.Format.XML.prototype.write.apply(this.format,[this.format.writeNode("wfs:GetFeature",a)]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},setFeatureType:function(a){this.featureType=a;this.format.featureType=a},setGeometryName:function(a){this.geometryName=a;this.format.geometryName=a},handleRead:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);if(b.callback){var c=
2511 a.priv;200<=c.status&&300>c.status?(c=this.parseResponse(c,b.readOptions))&&!1!==c.success?(b.readOptions&&"object"==b.readOptions.output?OpenLayers.Util.extend(a,c):a.features=c,a.code=OpenLayers.Protocol.Response.SUCCESS):(a.code=OpenLayers.Protocol.Response.FAILURE,a.error=c):a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseResponse:function(a,b){var c=a.responseXML;if(!c||!c.documentElement)c=a.responseText;if(!c||0>=c.length)return null;c=null!==this.readFormat?this.readFormat.read(c):
2512 this.format.read(c,b);if(!this.featureNS){var d=this.readFormat||this.format;this.featureNS=d.featureNS;d.autoConfig=!1;this.geometryName||this.setGeometryName(d.geometryName)}return c},commit:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);var c=new OpenLayers.Protocol.Response({requestType:"commit",reqFeatures:a});c.priv=OpenLayers.Request.POST({url:b.url,headers:b.headers,data:this.format.write(a,b),callback:this.createCallback(this.handleCommit,c,b)});
2513 return c},handleCommit:function(a,b){if(b.callback){var c=a.priv,d=c.responseXML;if(!d||!d.documentElement)d=c.responseText;c=this.format.read(d)||{};a.insertIds=c.insertIds||[];c.success?a.code=OpenLayers.Protocol.Response.SUCCESS:(a.code=OpenLayers.Protocol.Response.FAILURE,a.error=c);b.callback.call(b.scope,a)}},filterDelete:function(a,b){b=OpenLayers.Util.extend({},b);OpenLayers.Util.applyDefaults(b,this.options);new OpenLayers.Protocol.Response({requestType:"commit"});var c=this.format.createElementNSPlus("wfs:Transaction",
2514 {attributes:{service:"WFS",version:this.version}}),d=this.format.createElementNSPlus("wfs:Delete",{attributes:{typeName:(b.featureNS?this.featurePrefix+":":"")+b.featureType}});b.featureNS&&d.setAttribute("xmlns:"+this.featurePrefix,b.featureNS);var e=this.format.writeNode("ogc:Filter",a);d.appendChild(e);c.appendChild(d);c=OpenLayers.Format.XML.prototype.write.apply(this.format,[c]);return OpenLayers.Request.POST({url:this.url,callback:b.callback||function(){},data:c})},abort:function(a){a&&a.priv.abort()},
2515 CLASS_NAME:"OpenLayers.Protocol.WFS.v1"});OpenLayers.Handler.Point=OpenLayers.Class(OpenLayers.Handler,{point:null,layer:null,multi:!1,citeCompliant:!1,mouseDown:!1,stoppedDown:null,lastDown:null,lastUp:null,persist:!1,stopDown:!1,stopUp:!1,layerOptions:null,pixelTolerance:5,touch:!1,lastTouchPx:null,initialize:function(a,b,c){if(!c||!c.layerOptions||!c.layerOptions.styleMap)this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{});OpenLayers.Handler.prototype.initialize.apply(this,arguments)},activate:function(){if(!OpenLayers.Handler.prototype.activate.apply(this,
2516 arguments))return!1;var a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions);this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a);this.map.addLayer(this.layer);return!0},createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.callback("create",[this.point.geometry,this.point]);this.point.geometry.clearBounds();
2517 this.layer.addFeatures([this.point],{silent:!0})},deactivate:function(){if(!OpenLayers.Handler.prototype.deactivate.apply(this,arguments))return!1;this.cancel();null!=this.layer.map&&(this.destroyFeature(!0),this.layer.destroy(!1));this.layer=null;this.touch=!1;return!0},destroyFeature:function(a){this.layer&&(a||!this.persist)&&this.layer.destroyFeatures();this.point=null},destroyPersistedFeature:function(){var a=this.layer;a&&1<a.features.length&&this.layer.features[0].destroy()},finalize:function(a){this.mouseDown=
2518 !1;this.lastTouchPx=this.lastUp=this.lastDown=null;this.callback(a?"cancel":"done",[this.geometryClone()]);this.destroyFeature(a)},cancel:function(){this.finalize(!0)},click:function(a){OpenLayers.Event.stop(a);return!1},dblclick:function(a){OpenLayers.Event.stop(a);return!1},modifyFeature:function(a){this.point||this.createFeature(a);a=this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=a.lon;this.point.geometry.y=a.lat;this.callback("modify",[this.point.geometry,this.point,!1]);this.point.geometry.clearBounds();
2519 this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.point,this.style)},getGeometry:function(){var a=this.point&&this.point.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiPoint([a]));return a},geometryClone:function(){var a=this.getGeometry();return a&&a.clone()},mousedown:function(a){return this.down(a)},touchstart:function(a){this.touch||(this.touch=!0,this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,mousemove:this.mousemove,click:this.click,dblclick:this.dblclick,
2520 scope:this}));this.lastTouchPx=a.xy;return this.down(a)},mousemove:function(a){return this.move(a)},touchmove:function(a){this.lastTouchPx=a.xy;return this.move(a)},mouseup:function(a){return this.up(a)},touchend:function(a){a.xy=this.lastTouchPx;return this.up(a)},down:function(a){this.mouseDown=!0;this.lastDown=a.xy;this.touch||this.modifyFeature(a.xy);this.stoppedDown=this.stopDown;return!this.stopDown},move:function(a){!this.touch&&(!this.mouseDown||this.stoppedDown)&&this.modifyFeature(a.xy);
2521 return!0},up:function(a){this.mouseDown=!1;this.stoppedDown=this.stopDown;return this.checkModifiers(a)&&(!this.lastUp||!this.lastUp.equals(a.xy))&&this.lastDown&&this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)?(this.touch&&this.modifyFeature(a.xy),this.persist&&this.destroyPersistedFeature(),this.lastUp=a.xy,this.finalize(),!this.stopUp):!0},mouseout:function(a){OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)&&(this.stoppedDown=this.stopDown,this.mouseDown=!1)},passesTolerance:function(a,
2522 b,c){var d=!0;null!=c&&a&&b&&a.distanceTo(b)>c&&(d=!1);return d},CLASS_NAME:"OpenLayers.Handler.Point"});OpenLayers.Handler.Path=OpenLayers.Class(OpenLayers.Handler.Point,{line:null,maxVertices:null,doubleTouchTolerance:20,freehand:!1,freehandToggle:"shiftKey",timerId:null,redoStack:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([this.point.geometry]));this.callback("create",[this.point.geometry,this.getSketch()]);
2523 this.point.geometry.clearBounds();this.layer.addFeatures([this.line,this.point],{silent:!0})},destroyFeature:function(a){OpenLayers.Handler.Point.prototype.destroyFeature.call(this,a);this.line=null},destroyPersistedFeature:function(){var a=this.layer;a&&2<a.features.length&&this.layer.features[0].destroy()},removePoint:function(){this.point&&this.layer.removeFeatures([this.point])},addPoint:function(a){this.layer.removeFeatures([this.point]);a=this.layer.getLonLatFromViewPortPx(a);this.point=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a.lon,
2524 a.lat));this.line.geometry.addComponent(this.point.geometry,this.line.geometry.components.length);this.layer.addFeatures([this.point]);this.callback("point",[this.point.geometry,this.getGeometry()]);this.callback("modify",[this.point.geometry,this.getSketch()]);this.drawFeature();delete this.redoStack},insertXY:function(a,b){this.line.geometry.addComponent(new OpenLayers.Geometry.Point(a,b),this.getCurrentPointIndex());this.drawFeature();delete this.redoStack},insertDeltaXY:function(a,b){var c=this.line.geometry.components[this.getCurrentPointIndex()-
2525 1];c&&(!isNaN(c.x)&&!isNaN(c.y))&&this.insertXY(c.x+a,c.y+b)},insertDirectionLength:function(a,b){var a=a*(Math.PI/180),c=b*Math.cos(a),d=b*Math.sin(a);this.insertDeltaXY(c,d)},insertDeflectionLength:function(a,b){var c=this.getCurrentPointIndex()-1;if(0<c){var d=this.line.geometry.components[c],c=this.line.geometry.components[c-1];this.insertDirectionLength(180*Math.atan2(d.y-c.y,d.x-c.x)/Math.PI+a,b)}},getCurrentPointIndex:function(){return this.line.geometry.components.length-1},undo:function(){var a=
2526 this.line.geometry,b=a.components,c=this.getCurrentPointIndex()-1,b=b[c];if(a=a.removeComponent(b))this.redoStack||(this.redoStack=[]),this.redoStack.push(b),this.drawFeature();return a},redo:function(){var a=this.redoStack&&this.redoStack.pop();a&&(this.line.geometry.addComponent(a,this.getCurrentPointIndex()),this.drawFeature());return!!a},freehandMode:function(a){return this.freehandToggle&&a[this.freehandToggle]?!this.freehand:this.freehand},modifyFeature:function(a,b){this.line||this.createFeature(a);
2527 var c=this.layer.getLonLatFromViewPortPx(a);this.point.geometry.x=c.lon;this.point.geometry.y=c.lat;this.callback("modify",[this.point.geometry,this.getSketch(),b]);this.point.geometry.clearBounds();this.drawFeature()},drawFeature:function(){this.layer.drawFeature(this.line,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.line},getGeometry:function(){var a=this.line&&this.line.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiLineString([a]));return a},
2528 touchstart:function(a){if(this.timerId&&this.passesTolerance(this.lastTouchPx,a.xy,this.doubleTouchTolerance))return this.finishGeometry(),window.clearTimeout(this.timerId),this.timerId=null,!1;this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);this.timerId=window.setTimeout(OpenLayers.Function.bind(function(){this.timerId=null},this),300);return OpenLayers.Handler.Point.prototype.touchstart.call(this,a)},down:function(a){var b=this.stopDown;this.freehandMode(a)&&(b=!0,this.touch&&
2529 (this.modifyFeature(a.xy,!!this.lastUp),OpenLayers.Event.stop(a)));!this.touch&&(!this.lastDown||!this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance))&&this.modifyFeature(a.xy,!!this.lastUp);this.mouseDown=!0;this.lastDown=a.xy;this.stoppedDown=b;return!b},move:function(a){if(this.stoppedDown&&this.freehandMode(a))return this.persist&&this.destroyPersistedFeature(),this.maxVertices&&this.line&&this.line.geometry.components.length===this.maxVertices?(this.removePoint(),this.finalize()):this.addPoint(a.xy),
2530 !1;!this.touch&&(!this.mouseDown||this.stoppedDown)&&this.modifyFeature(a.xy,!!this.lastUp);return!0},up:function(a){if(this.mouseDown&&(!this.lastUp||!this.lastUp.equals(a.xy)))this.stoppedDown&&this.freehandMode(a)?(this.persist&&this.destroyPersistedFeature(),this.removePoint(),this.finalize()):this.passesTolerance(this.lastDown,a.xy,this.pixelTolerance)&&(this.touch&&this.modifyFeature(a.xy),null==this.lastUp&&this.persist&&this.destroyPersistedFeature(),this.addPoint(a.xy),this.lastUp=a.xy,this.line.geometry.components.length===
2531 this.maxVertices+1&&this.finishGeometry());this.stoppedDown=this.stopDown;this.mouseDown=!1;return!this.stopUp},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-1]);this.removePoint();this.finalize()},dblclick:function(a){this.freehandMode(a)||this.finishGeometry();return!1},CLASS_NAME:"OpenLayers.Handler.Path"});OpenLayers.Spherical=OpenLayers.Spherical||{};OpenLayers.Spherical.DEFAULT_RADIUS=6378137;OpenLayers.Spherical.computeDistanceBetween=function(a,b,c){var c=c||OpenLayers.Spherical.DEFAULT_RADIUS,d=Math.sin(Math.PI*(b.lon-a.lon)/360),e=Math.sin(Math.PI*(b.lat-a.lat)/360),a=e*e+d*d*Math.cos(Math.PI*a.lat/180)*Math.cos(Math.PI*b.lat/180);return 2*c*Math.atan2(Math.sqrt(a),Math.sqrt(1-a))};
2532 OpenLayers.Spherical.computeHeading=function(a,b){var c=Math.sin(Math.PI*(a.lon-b.lon)/180)*Math.cos(Math.PI*b.lat/180),d=Math.cos(Math.PI*a.lat/180)*Math.sin(Math.PI*b.lat/180)-Math.sin(Math.PI*a.lat/180)*Math.cos(Math.PI*b.lat/180)*Math.cos(Math.PI*(a.lon-b.lon)/180);return 180*Math.atan2(c,d)/Math.PI};OpenLayers.Control.CacheWrite=OpenLayers.Class(OpenLayers.Control,{layers:null,imageFormat:"image/png",quotaRegEx:/quota/i,setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);var b,c=this.layers||a.layers;for(b=c.length-1;0<=b;--b)this.addLayer({layer:c[b]});if(!this.layers)a.events.on({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this})},addLayer:function(a){a.layer.events.on({tileloadstart:this.makeSameOrigin,tileloaded:this.cache,scope:this})},removeLayer:function(a){a.layer.events.un({tileloadstart:this.makeSameOrigin,
2533 tileloaded:this.cache,scope:this})},makeSameOrigin:function(a){if(this.active&&(a=a.tile,a instanceof OpenLayers.Tile.Image&&!a.crossOriginKeyword&&"data:"!==a.url.substr(0,5))){var b=OpenLayers.Request.makeSameOrigin(a.url,OpenLayers.ProxyHost);OpenLayers.Control.CacheWrite.urlMap[b]=a.url;a.url=b}},cache:function(a){if(this.active&&window.localStorage&&(a=a.tile,a instanceof OpenLayers.Tile.Image&&"data:"!==a.url.substr(0,5)))try{var b=a.getCanvasContext();if(b){var c=OpenLayers.Control.CacheWrite.urlMap;
2534 window.localStorage.setItem("olCache_"+(c[a.url]||a.url),b.canvas.toDataURL(this.imageFormat));delete c[a.url]}}catch(d){(b=d.name||d.message)&&this.quotaRegEx.test(b)?this.events.triggerEvent("cachefull",{tile:a}):OpenLayers.Console.error(d.toString())}},destroy:function(){if(this.layers||this.map){var a,b=this.layers||this.map.layers;for(a=b.length-1;0<=a;--a)this.removeLayer({layer:b[a]})}this.map&&this.map.events.un({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this});OpenLayers.Control.prototype.destroy.apply(this,
2535 arguments)},CLASS_NAME:"OpenLayers.Control.CacheWrite"});OpenLayers.Control.CacheWrite.clearCache=function(){if(window.localStorage){var a,b;for(a=window.localStorage.length-1;0<=a;--a)b=window.localStorage.key(a),"olCache_"===b.substr(0,8)&&window.localStorage.removeItem(b)}};OpenLayers.Control.CacheWrite.urlMap={};OpenLayers.Format.Context=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{layerOptions:null,layerParams:null,read:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.read.apply(this,arguments);if(b&&b.map)if(this.context=c,b.map instanceof OpenLayers.Map)c=this.mergeContextToMap(c,b.map);else{var d=b.map;if(OpenLayers.Util.isElement(d)||"string"==typeof d)d={div:d};c=this.contextToMap(c,d)}return c},getLayerFromContext:function(a){var b,c,d={queryable:a.queryable,visibility:a.visibility,
2536 maxExtent:a.maxExtent,metadata:OpenLayers.Util.applyDefaults(a.metadata,{styles:a.styles,formats:a.formats,"abstract":a["abstract"],dataURL:a.dataURL}),numZoomLevels:a.numZoomLevels,units:a.units,isBaseLayer:a.isBaseLayer,opacity:a.opacity,displayInLayerSwitcher:a.displayInLayerSwitcher,singleTile:a.singleTile,tileSize:a.tileSize?new OpenLayers.Size(a.tileSize.width,a.tileSize.height):void 0,minScale:a.minScale||a.maxScaleDenominator,maxScale:a.maxScale||a.minScaleDenominator,srs:a.srs,dimensions:a.dimensions,
2537 metadataURL:a.metadataURL};this.layerOptions&&OpenLayers.Util.applyDefaults(d,this.layerOptions);var e={layers:a.name,transparent:a.transparent,version:a.version};if(a.formats&&0<a.formats.length){e.format=a.formats[0].value;b=0;for(c=a.formats.length;b<c;b++){var f=a.formats[b];if(!0==f.current){e.format=f.value;break}}}if(a.styles&&0<a.styles.length){b=0;for(c=a.styles.length;b<c;b++)if(f=a.styles[b],!0==f.current){f.href?e.sld=f.href:f.body?e.sld_body=f.body:e.styles=f.name;break}}this.layerParams&&
2538 OpenLayers.Util.applyDefaults(e,this.layerParams);b=null;c=a.service;c==OpenLayers.Format.Context.serviceTypes.WFS?(d.strategies=[new OpenLayers.Strategy.BBOX],d.protocol=new OpenLayers.Protocol.WFS({url:a.url,featurePrefix:a.name.split(":")[0],featureType:a.name.split(":").pop()}),b=new OpenLayers.Layer.Vector(a.title||a.name,d)):c==OpenLayers.Format.Context.serviceTypes.KML?(d.strategies=[new OpenLayers.Strategy.Fixed],d.protocol=new OpenLayers.Protocol.HTTP({url:a.url,format:new OpenLayers.Format.KML}),
2539 b=new OpenLayers.Layer.Vector(a.title||a.name,d)):c==OpenLayers.Format.Context.serviceTypes.GML?(d.strategies=[new OpenLayers.Strategy.Fixed],d.protocol=new OpenLayers.Protocol.HTTP({url:a.url,format:new OpenLayers.Format.GML}),b=new OpenLayers.Layer.Vector(a.title||a.name,d)):a.features?(b=new OpenLayers.Layer.Vector(a.title||a.name,d),b.addFeatures(a.features)):!0!==a.categoryLayer&&(b=new OpenLayers.Layer.WMS(a.title||a.name,a.url,e,d));return b},getLayersFromContext:function(a){for(var b=[],c=
2540 0,d=a.length;c<d;c++){var e=this.getLayerFromContext(a[c]);null!==e&&b.push(e)}return b},contextToMap:function(a,b){b=OpenLayers.Util.applyDefaults({maxExtent:a.maxExtent,projection:a.projection,units:a.units},b);b.maxExtent&&(b.maxResolution=b.maxExtent.getWidth()/OpenLayers.Map.TILE_WIDTH);b.metadata={contactInformation:a.contactInformation,"abstract":a["abstract"],keywords:a.keywords,logo:a.logo,descriptionURL:a.descriptionURL};var c=new OpenLayers.Map(b);c.addLayers(this.getLayersFromContext(a.layersContext));
2541 c.setCenter(a.bounds.getCenterLonLat(),c.getZoomForExtent(a.bounds,!0));return c},mergeContextToMap:function(a,b){b.addLayers(this.getLayersFromContext(a.layersContext));return b},write:function(a,b){a=this.toContext(a);return OpenLayers.Format.XML.VersionedOGC.prototype.write.apply(this,arguments)},CLASS_NAME:"OpenLayers.Format.Context"});
2542 OpenLayers.Format.Context.serviceTypes={WMS:"urn:ogc:serviceType:WMS",WFS:"urn:ogc:serviceType:WFS",WCS:"urn:ogc:serviceType:WCS",GML:"urn:ogc:serviceType:GML",SLD:"urn:ogc:serviceType:SLD",FES:"urn:ogc:serviceType:FES",KML:"urn:ogc:serviceType:KML"};OpenLayers.Format.WMC=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"1.1.0",layerToContext:function(a){var b=this.getParser(),c={queryable:a.queryable,visibility:a.visibility,name:a.params.LAYERS,title:a.name,"abstract":a.metadata["abstract"],dataURL:a.metadata.dataURL,metadataURL:a.metadataURL,server:{version:a.params.VERSION,url:a.url},maxExtent:a.maxExtent,transparent:a.params.TRANSPARENT,numZoomLevels:a.numZoomLevels,units:a.units,isBaseLayer:a.isBaseLayer,opacity:1==a.opacity?void 0:
2543 a.opacity,displayInLayerSwitcher:a.displayInLayerSwitcher,singleTile:a.singleTile,tileSize:a.singleTile||!a.tileSize?void 0:{width:a.tileSize.w,height:a.tileSize.h},minScale:a.options.resolutions||a.options.scales||a.options.maxResolution||a.options.minScale?a.minScale:void 0,maxScale:a.options.resolutions||a.options.scales||a.options.minResolution||a.options.maxScale?a.maxScale:void 0,formats:[],styles:[],srs:a.srs,dimensions:a.dimensions};a.metadata.servertitle&&(c.server.title=a.metadata.servertitle);
2544 if(a.metadata.formats&&0<a.metadata.formats.length)for(var d=0,e=a.metadata.formats.length;d<e;d++){var f=a.metadata.formats[d];c.formats.push({value:f.value,current:f.value==a.params.FORMAT})}else c.formats.push({value:a.params.FORMAT,current:!0});if(a.metadata.styles&&0<a.metadata.styles.length){d=0;for(e=a.metadata.styles.length;d<e;d++)b=a.metadata.styles[d],b.current=b.href==a.params.SLD||b.body==a.params.SLD_BODY||b.name==a.params.STYLES?!0:!1,c.styles.push(b)}else c.styles.push({href:a.params.SLD,
2545 body:a.params.SLD_BODY,name:a.params.STYLES||b.defaultStyleName,title:b.defaultStyleTitle,current:!0});return c},toContext:function(a){var b={},c=a.layers;if("OpenLayers.Map"==a.CLASS_NAME){var d=a.metadata||{};b.size=a.getSize();b.bounds=a.getExtent();b.projection=a.projection;b.title=a.title;b.keywords=d.keywords;b["abstract"]=d["abstract"];b.logo=d.logo;b.descriptionURL=d.descriptionURL;b.contactInformation=d.contactInformation;b.maxExtent=a.maxExtent}else OpenLayers.Util.applyDefaults(b,a),void 0!=
2546 b.layers&&delete b.layers;void 0==b.layersContext&&(b.layersContext=[]);if(void 0!=c&&OpenLayers.Util.isArray(c)){a=0;for(d=c.length;a<d;a++){var e=c[a];e instanceof OpenLayers.Layer.WMS&&b.layersContext.push(this.layerToContext(e))}}return b},CLASS_NAME:"OpenLayers.Format.WMC"});OpenLayers.Format.WMC.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ol:"http://openlayers.org/context",wmc:"http://www.opengis.net/context",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"",getNamespacePrefix:function(a){var b=null;if(null==a)b=this.namespaces[this.defaultPrefix];else for(b in this.namespaces)if(this.namespaces[b]==a)break;return b},defaultPrefix:"wmc",rootPrefix:null,defaultStyleName:"",
2547 defaultStyleTitle:"Default",initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a=a.documentElement;this.rootPrefix=a.prefix;var b={version:a.getAttribute("version")};this.runChildNodes(b,a);return b},runChildNodes:function(a,b){for(var c=b.childNodes,d,e,f,g=0,h=c.length;g<h;++g)d=c[g],1==d.nodeType&&(e=this.getNamespacePrefix(d.namespaceURI),f=d.nodeName.split(":").pop(),
2548 (e=this["read_"+e+"_"+f])&&e.apply(this,[a,d]))},read_wmc_General:function(a,b){this.runChildNodes(a,b)},read_wmc_BoundingBox:function(a,b){a.projection=b.getAttribute("SRS");a.bounds=new OpenLayers.Bounds(b.getAttribute("minx"),b.getAttribute("miny"),b.getAttribute("maxx"),b.getAttribute("maxy"))},read_wmc_LayerList:function(a,b){a.layersContext=[];this.runChildNodes(a,b)},read_wmc_Layer:function(a,b){var c={visibility:"1"!=b.getAttribute("hidden"),queryable:"1"==b.getAttribute("queryable"),formats:[],
2549 styles:[],metadata:{}};this.runChildNodes(c,b);a.layersContext.push(c)},read_wmc_Extension:function(a,b){this.runChildNodes(a,b)},read_ol_units:function(a,b){a.units=this.getChildValue(b)},read_ol_maxExtent:function(a,b){var c=new OpenLayers.Bounds(b.getAttribute("minx"),b.getAttribute("miny"),b.getAttribute("maxx"),b.getAttribute("maxy"));a.maxExtent=c},read_ol_transparent:function(a,b){a.transparent=this.getChildValue(b)},read_ol_numZoomLevels:function(a,b){a.numZoomLevels=parseInt(this.getChildValue(b))},
2550 read_ol_opacity:function(a,b){a.opacity=parseFloat(this.getChildValue(b))},read_ol_singleTile:function(a,b){a.singleTile="true"==this.getChildValue(b)},read_ol_tileSize:function(a,b){var c={width:b.getAttribute("width"),height:b.getAttribute("height")};a.tileSize=c},read_ol_isBaseLayer:function(a,b){a.isBaseLayer="true"==this.getChildValue(b)},read_ol_displayInLayerSwitcher:function(a,b){a.displayInLayerSwitcher="true"==this.getChildValue(b)},read_wmc_Server:function(a,b){a.version=b.getAttribute("version");
2551 a.url=this.getOnlineResource_href(b);a.metadata.servertitle=b.getAttribute("title")},read_wmc_FormatList:function(a,b){this.runChildNodes(a,b)},read_wmc_Format:function(a,b){var c={value:this.getChildValue(b)};"1"==b.getAttribute("current")&&(c.current=!0);a.formats.push(c)},read_wmc_StyleList:function(a,b){this.runChildNodes(a,b)},read_wmc_Style:function(a,b){var c={};this.runChildNodes(c,b);"1"==b.getAttribute("current")&&(c.current=!0);a.styles.push(c)},read_wmc_SLD:function(a,b){this.runChildNodes(a,
2552 b)},read_sld_StyledLayerDescriptor:function(a,b){var c=OpenLayers.Format.XML.prototype.write.apply(this,[b]);a.body=c},read_sld_FeatureTypeStyle:function(a,b){var c=OpenLayers.Format.XML.prototype.write.apply(this,[b]);a.body=c},read_wmc_OnlineResource:function(a,b){a.href=this.getAttributeNS(b,this.namespaces.xlink,"href")},read_wmc_Name:function(a,b){var c=this.getChildValue(b);c&&(a.name=c)},read_wmc_Title:function(a,b){var c=this.getChildValue(b);c&&(a.title=c)},read_wmc_MetadataURL:function(a,
2553 b){a.metadataURL=this.getOnlineResource_href(b)},read_wmc_KeywordList:function(a,b){a.keywords=[];this.runChildNodes(a.keywords,b)},read_wmc_Keyword:function(a,b){a.push(this.getChildValue(b))},read_wmc_Abstract:function(a,b){var c=this.getChildValue(b);c&&(a["abstract"]=c)},read_wmc_LogoURL:function(a,b){a.logo={width:b.getAttribute("width"),height:b.getAttribute("height"),format:b.getAttribute("format"),href:this.getOnlineResource_href(b)}},read_wmc_DescriptionURL:function(a,b){a.descriptionURL=
2554 this.getOnlineResource_href(b)},read_wmc_ContactInformation:function(a,b){var c={};this.runChildNodes(c,b);a.contactInformation=c},read_wmc_ContactPersonPrimary:function(a,b){var c={};this.runChildNodes(c,b);a.personPrimary=c},read_wmc_ContactPerson:function(a,b){var c=this.getChildValue(b);c&&(a.person=c)},read_wmc_ContactOrganization:function(a,b){var c=this.getChildValue(b);c&&(a.organization=c)},read_wmc_ContactPosition:function(a,b){var c=this.getChildValue(b);c&&(a.position=c)},read_wmc_ContactAddress:function(a,
2555 b){var c={};this.runChildNodes(c,b);a.contactAddress=c},read_wmc_AddressType:function(a,b){var c=this.getChildValue(b);c&&(a.type=c)},read_wmc_Address:function(a,b){var c=this.getChildValue(b);c&&(a.address=c)},read_wmc_City:function(a,b){var c=this.getChildValue(b);c&&(a.city=c)},read_wmc_StateOrProvince:function(a,b){var c=this.getChildValue(b);c&&(a.stateOrProvince=c)},read_wmc_PostCode:function(a,b){var c=this.getChildValue(b);c&&(a.postcode=c)},read_wmc_Country:function(a,b){var c=this.getChildValue(b);
2556 c&&(a.country=c)},read_wmc_ContactVoiceTelephone:function(a,b){var c=this.getChildValue(b);c&&(a.phone=c)},read_wmc_ContactFacsimileTelephone:function(a,b){var c=this.getChildValue(b);c&&(a.fax=c)},read_wmc_ContactElectronicMailAddress:function(a,b){var c=this.getChildValue(b);c&&(a.email=c)},read_wmc_DataURL:function(a,b){a.dataURL=this.getOnlineResource_href(b)},read_wmc_LegendURL:function(a,b){var c={width:b.getAttribute("width"),height:b.getAttribute("height"),format:b.getAttribute("format"),
2557 href:this.getOnlineResource_href(b)};a.legend=c},read_wmc_DimensionList:function(a,b){a.dimensions={};this.runChildNodes(a.dimensions,b)},read_wmc_Dimension:function(a,b){var c={name:b.getAttribute("name").toLowerCase(),units:b.getAttribute("units")||"",unitSymbol:b.getAttribute("unitSymbol")||"",userValue:b.getAttribute("userValue")||"",nearestValue:"1"===b.getAttribute("nearestValue"),multipleValues:"1"===b.getAttribute("multipleValues"),current:"1"===b.getAttribute("current"),"default":b.getAttribute("default")||
2558 ""},d=this.getChildValue(b);c.values=d.split(",");a[c.name]=c},write:function(a,b){var c=this.createElementDefaultNS("ViewContext");this.setAttributes(c,{version:this.VERSION,id:b&&"string"==typeof b.id?b.id:OpenLayers.Util.createUniqueID("OpenLayers_Context_")});this.setAttributeNS(c,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);c.appendChild(this.write_wmc_General(a));c.appendChild(this.write_wmc_LayerList(a));return OpenLayers.Format.XML.prototype.write.apply(this,[c])},createElementDefaultNS:function(a,
2559 b,c){a=this.createElementNS(this.namespaces[this.defaultPrefix],a);b&&a.appendChild(this.createTextNode(b));c&&this.setAttributes(a,c);return a},setAttributes:function(a,b){var c,d;for(d in b)c=b[d].toString(),c.match(/[A-Z]/)?this.setAttributeNS(a,null,d,c):a.setAttribute(d,c)},write_wmc_General:function(a){var b=this.createElementDefaultNS("General");a.size&&b.appendChild(this.createElementDefaultNS("Window",null,{width:a.size.w,height:a.size.h}));var c=a.bounds;b.appendChild(this.createElementDefaultNS("BoundingBox",
2560 null,{minx:c.left.toPrecision(18),miny:c.bottom.toPrecision(18),maxx:c.right.toPrecision(18),maxy:c.top.toPrecision(18),SRS:a.projection}));b.appendChild(this.createElementDefaultNS("Title",a.title));a.keywords&&b.appendChild(this.write_wmc_KeywordList(a.keywords));a["abstract"]&&b.appendChild(this.createElementDefaultNS("Abstract",a["abstract"]));a.logo&&b.appendChild(this.write_wmc_URLType("LogoURL",a.logo.href,a.logo));a.descriptionURL&&b.appendChild(this.write_wmc_URLType("DescriptionURL",a.descriptionURL));
2561 a.contactInformation&&b.appendChild(this.write_wmc_ContactInformation(a.contactInformation));b.appendChild(this.write_ol_MapExtension(a));return b},write_wmc_KeywordList:function(a){for(var b=this.createElementDefaultNS("KeywordList"),c=0,d=a.length;c<d;c++)b.appendChild(this.createElementDefaultNS("Keyword",a[c]));return b},write_wmc_ContactInformation:function(a){var b=this.createElementDefaultNS("ContactInformation");a.personPrimary&&b.appendChild(this.write_wmc_ContactPersonPrimary(a.personPrimary));
2562 a.position&&b.appendChild(this.createElementDefaultNS("ContactPosition",a.position));a.contactAddress&&b.appendChild(this.write_wmc_ContactAddress(a.contactAddress));a.phone&&b.appendChild(this.createElementDefaultNS("ContactVoiceTelephone",a.phone));a.fax&&b.appendChild(this.createElementDefaultNS("ContactFacsimileTelephone",a.fax));a.email&&b.appendChild(this.createElementDefaultNS("ContactElectronicMailAddress",a.email));return b},write_wmc_ContactPersonPrimary:function(a){var b=this.createElementDefaultNS("ContactPersonPrimary");
2563 a.person&&b.appendChild(this.createElementDefaultNS("ContactPerson",a.person));a.organization&&b.appendChild(this.createElementDefaultNS("ContactOrganization",a.organization));return b},write_wmc_ContactAddress:function(a){var b=this.createElementDefaultNS("ContactAddress");a.type&&b.appendChild(this.createElementDefaultNS("AddressType",a.type));a.address&&b.appendChild(this.createElementDefaultNS("Address",a.address));a.city&&b.appendChild(this.createElementDefaultNS("City",a.city));a.stateOrProvince&&
2564 b.appendChild(this.createElementDefaultNS("StateOrProvince",a.stateOrProvince));a.postcode&&b.appendChild(this.createElementDefaultNS("PostCode",a.postcode));a.country&&b.appendChild(this.createElementDefaultNS("Country",a.country));return b},write_ol_MapExtension:function(a){var b=this.createElementDefaultNS("Extension");if(a=a.maxExtent){var c=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(c,{minx:a.left.toPrecision(18),miny:a.bottom.toPrecision(18),maxx:a.right.toPrecision(18),
2565 maxy:a.top.toPrecision(18)});b.appendChild(c)}return b},write_wmc_LayerList:function(a){for(var b=this.createElementDefaultNS("LayerList"),c=0,d=a.layersContext.length;c<d;++c)b.appendChild(this.write_wmc_Layer(a.layersContext[c]));return b},write_wmc_Layer:function(a){var b=this.createElementDefaultNS("Layer",null,{queryable:a.queryable?"1":"0",hidden:a.visibility?"0":"1"});b.appendChild(this.write_wmc_Server(a));b.appendChild(this.createElementDefaultNS("Name",a.name));b.appendChild(this.createElementDefaultNS("Title",
2566 a.title));a["abstract"]&&b.appendChild(this.createElementDefaultNS("Abstract",a["abstract"]));a.dataURL&&b.appendChild(this.write_wmc_URLType("DataURL",a.dataURL));a.metadataURL&&b.appendChild(this.write_wmc_URLType("MetadataURL",a.metadataURL));return b},write_wmc_LayerExtension:function(a){var b=this.createElementDefaultNS("Extension"),c=a.maxExtent,d=this.createElementNS(this.namespaces.ol,"ol:maxExtent");this.setAttributes(d,{minx:c.left.toPrecision(18),miny:c.bottom.toPrecision(18),maxx:c.right.toPrecision(18),
2567 maxy:c.top.toPrecision(18)});b.appendChild(d);a.tileSize&&!a.singleTile&&(c=this.createElementNS(this.namespaces.ol,"ol:tileSize"),this.setAttributes(c,a.tileSize),b.appendChild(c));for(var c="transparent numZoomLevels units isBaseLayer opacity displayInLayerSwitcher singleTile".split(" "),e=0,f=c.length;e<f;++e)(d=this.createOLPropertyNode(a,c[e]))&&b.appendChild(d);return b},createOLPropertyNode:function(a,b){var c=null;null!=a[b]&&(c=this.createElementNS(this.namespaces.ol,"ol:"+b),c.appendChild(this.createTextNode(a[b].toString())));
2568 return c},write_wmc_Server:function(a){var a=a.server,b=this.createElementDefaultNS("Server"),c={service:"OGC:WMS",version:a.version};a.title&&(c.title=a.title);this.setAttributes(b,c);b.appendChild(this.write_wmc_OnlineResource(a.url));return b},write_wmc_URLType:function(a,b,c){a=this.createElementDefaultNS(a);a.appendChild(this.write_wmc_OnlineResource(b));if(c)for(var b=["width","height","format"],d=0;d<b.length;d++)b[d]in c&&a.setAttribute(b[d],c[b[d]]);return a},write_wmc_DimensionList:function(a){var b=
2569 this.createElementDefaultNS("DimensionList"),c;for(c in a.dimensions){var d={},e=a.dimensions[c],f;for(f in e)d[f]="boolean"==typeof e[f]?Number(e[f]):e[f];e="";d.values&&(e=d.values.join(","),delete d.values);b.appendChild(this.createElementDefaultNS("Dimension",e,d))}return b},write_wmc_FormatList:function(a){for(var b=this.createElementDefaultNS("FormatList"),c=0,d=a.formats.length;c<d;c++){var e=a.formats[c];b.appendChild(this.createElementDefaultNS("Format",e.value,e.current&&!0==e.current?{current:"1"}:
2570 null))}return b},write_wmc_StyleList:function(a){var b=this.createElementDefaultNS("StyleList");if((a=a.styles)&&OpenLayers.Util.isArray(a))for(var c,d=0,e=a.length;d<e;d++){var f=a[d],g=this.createElementDefaultNS("Style",null,f.current&&!0==f.current?{current:"1"}:null);f.href?(c=this.createElementDefaultNS("SLD"),f.name&&c.appendChild(this.createElementDefaultNS("Name",f.name)),f.title&&c.appendChild(this.createElementDefaultNS("Title",f.title)),f.legend&&c.appendChild(this.write_wmc_URLType("LegendURL",
2571 f.legend.href,f.legend)),f=this.write_wmc_OnlineResource(f.href),c.appendChild(f),g.appendChild(c)):f.body?(c=this.createElementDefaultNS("SLD"),f.name&&c.appendChild(this.createElementDefaultNS("Name",f.name)),f.title&&c.appendChild(this.createElementDefaultNS("Title",f.title)),f.legend&&c.appendChild(this.write_wmc_URLType("LegendURL",f.legend.href,f.legend)),f=OpenLayers.Format.XML.prototype.read.apply(this,[f.body]).documentElement,c.ownerDocument&&c.ownerDocument.importNode&&(f=c.ownerDocument.importNode(f,
2572 !0)),c.appendChild(f),g.appendChild(c)):(g.appendChild(this.createElementDefaultNS("Name",f.name)),g.appendChild(this.createElementDefaultNS("Title",f.title)),f["abstract"]&&g.appendChild(this.createElementDefaultNS("Abstract",f["abstract"])),f.legend&&g.appendChild(this.write_wmc_URLType("LegendURL",f.legend.href,f.legend)));b.appendChild(g)}return b},write_wmc_OnlineResource:function(a){var b=this.createElementDefaultNS("OnlineResource");this.setAttributeNS(b,this.namespaces.xlink,"xlink:type",
2573 "simple");this.setAttributeNS(b,this.namespaces.xlink,"xlink:href",a);return b},getOnlineResource_href:function(a){var b={},a=a.getElementsByTagName("OnlineResource");0<a.length&&this.read_wmc_OnlineResource(b,a[0]);return b.href},CLASS_NAME:"OpenLayers.Format.WMC.v1"});OpenLayers.Control.PanPanel=OpenLayers.Class(OpenLayers.Control.Panel,{slideFactor:50,slideRatio:null,initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);a={slideFactor:this.slideFactor,slideRatio:this.slideRatio};this.addControls([new OpenLayers.Control.Pan(OpenLayers.Control.Pan.NORTH,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.SOUTH,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.EAST,a),new OpenLayers.Control.Pan(OpenLayers.Control.Pan.WEST,a)])},
2574 CLASS_NAME:"OpenLayers.Control.PanPanel"});OpenLayers.Control.Attribution=OpenLayers.Class(OpenLayers.Control,{separator:", ",template:"${layers}",destroy:function(){this.map.events.un({removelayer:this.updateAttribution,addlayer:this.updateAttribution,changelayer:this.updateAttribution,changebaselayer:this.updateAttribution,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.map.events.on({changebaselayer:this.updateAttribution,changelayer:this.updateAttribution,
2575 addlayer:this.updateAttribution,removelayer:this.updateAttribution,scope:this});this.updateAttribution();return this.div},updateAttribution:function(){var a=[];if(this.map&&this.map.layers){for(var b=0,c=this.map.layers.length;b<c;b++){var d=this.map.layers[b];d.attribution&&d.getVisibility()&&-1===OpenLayers.Util.indexOf(a,d.attribution)&&a.push(d.attribution)}this.div.innerHTML=OpenLayers.String.format(this.template,{layers:a.join(this.separator)})}},CLASS_NAME:"OpenLayers.Control.Attribution"});OpenLayers.Kinetic=OpenLayers.Class({threshold:0,deceleration:0.0035,nbPoints:100,delay:200,points:void 0,timerId:void 0,initialize:function(a){OpenLayers.Util.extend(this,a)},begin:function(){OpenLayers.Animation.stop(this.timerId);this.timerId=void 0;this.points=[]},update:function(a){this.points.unshift({xy:a,tick:(new Date).getTime()});this.points.length>this.nbPoints&&this.points.pop()},end:function(a){for(var b,c=(new Date).getTime(),d=0,e=this.points.length,f;d<e;d++){f=this.points[d];if(c-
2576 f.tick>this.delay)break;b=f}if(b&&(d=(new Date).getTime()-b.tick,c=Math.sqrt(Math.pow(a.x-b.xy.x,2)+Math.pow(a.y-b.xy.y,2)),d=c/d,!(0==d||d<this.threshold)))return c=Math.asin((a.y-b.xy.y)/c),b.xy.x<=a.x&&(c=Math.PI-c),{speed:d,theta:c}},move:function(a,b){var c=a.speed,d=Math.cos(a.theta),e=-Math.sin(a.theta),f=(new Date).getTime(),g=0,h=0;this.timerId=OpenLayers.Animation.start(OpenLayers.Function.bind(function(){if(null!=this.timerId){var a=(new Date).getTime()-f,j=-this.deceleration*Math.pow(a,
2577 2)/2+c*a,k=j*d,j=j*e,l,m;l=!1;0>=-this.deceleration*a+c&&(OpenLayers.Animation.stop(this.timerId),this.timerId=null,l=!0);a=k-g;m=j-h;g=k;h=j;b(a,m,l)}},this))},CLASS_NAME:"OpenLayers.Kinetic"});OpenLayers.Layer.GeoRSS=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,icon:null,popupSize:null,useFeedTitle:!0,initialize:function(a,b,c){OpenLayers.Layer.Markers.prototype.initialize.apply(this,[a,c]);this.location=b;this.features=[]},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null},loadRSS:function(){this.loaded||(this.events.triggerEvent("loadstart"),OpenLayers.Request.GET({url:this.location,
2578 success:this.parseData,scope:this}),this.loaded=!0)},moveTo:function(a,b,c){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);this.visibility&&!this.loaded&&this.loadRSS()},parseData:function(a){var b=a.responseXML;if(!b||!b.documentElement)b=OpenLayers.Format.XML.prototype.read(a.responseText);if(this.useFeedTitle){a=null;try{a=b.getElementsByTagNameNS("*","title")[0].firstChild.nodeValue}catch(c){a=b.getElementsByTagName("title")[0].firstChild.nodeValue}a&&this.setName(a)}a={};OpenLayers.Util.extend(a,
2579 this.formatOptions);this.map&&!this.projection.equals(this.map.getProjectionObject())&&(a.externalProjection=this.projection,a.internalProjection=this.map.getProjectionObject());for(var b=(new OpenLayers.Format.GeoRSS(a)).read(b),a=0,d=b.length;a<d;a++){var e={},f=b[a];if(f.geometry){var g=f.attributes.title?f.attributes.title:"Untitled",h=f.attributes.description?f.attributes.description:"No description.",i=f.attributes.link?f.attributes.link:"",f=f.geometry.getBounds().getCenterLonLat();e.icon=
2580 null==this.icon?OpenLayers.Marker.defaultIcon():this.icon.clone();e.popupSize=this.popupSize?this.popupSize.clone():new OpenLayers.Size(250,120);if(g||h){e.title=g;e.description=h;var j='<div class="olLayerGeoRSSClose">[x]</div>',j=j+'<div class="olLayerGeoRSSTitle">';i&&(j+='<a class="link" href="'+i+'" target="_blank">');j+=g;i&&(j+="</a>");j+="</div>";j+='<div style="" class="olLayerGeoRSSDescription">';j+=h;j+="</div>";e.popupContentHTML=j}f=new OpenLayers.Feature(this,f,e);this.features.push(f);
2581 e=f.createMarker();e.events.register("click",f,this.markerClick);this.addMarker(e)}}this.events.triggerEvent("loadend")},markerClick:function(a){var b=this==this.layer.selectedFeature;this.layer.selectedFeature=!b?this:null;for(var c=0,d=this.layer.map.popups.length;c<d;c++)this.layer.map.removePopup(this.layer.map.popups[c]);b||(b=this.createPopup(),OpenLayers.Event.observe(b.div,"click",OpenLayers.Function.bind(function(){for(var a=0,b=this.layer.map.popups.length;a<b;a++)this.layer.map.removePopup(this.layer.map.popups[a])},
2582 this)),this.layer.map.addPopup(b));OpenLayers.Event.stop(a)},clearFeatures:function(){if(null!=this.features)for(;0<this.features.length;){var a=this.features[0];OpenLayers.Util.removeItem(this.features,a);a.destroy()}},CLASS_NAME:"OpenLayers.Layer.GeoRSS"});OpenLayers.Symbolizer.Point=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Point"});OpenLayers.Symbolizer.Line=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Line"});OpenLayers.Symbolizer.Text=OpenLayers.Class(OpenLayers.Symbolizer,{initialize:function(a){OpenLayers.Symbolizer.prototype.initialize.apply(this,arguments)},CLASS_NAME:"OpenLayers.Symbolizer.Text"});OpenLayers.Format.SLD.v1=OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0,{namespaces:{sld:"http://www.opengis.net/sld",ogc:"http://www.opengis.net/ogc",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"sld",schemaLocation:null,multipleSymbolizers:!1,featureTypeCounter:null,defaultSymbolizer:{fillColor:"#808080",fillOpacity:1,strokeColor:"#000000",strokeOpacity:1,strokeWidth:1,strokeDashstyle:"solid",pointRadius:3,
2583 graphicName:"square"},read:function(a,b){var b=OpenLayers.Util.applyDefaults(b,this.options),c={namedLayers:!0===b.namedLayersAsArray?[]:{}};this.readChildNodes(a,c);return c},readers:OpenLayers.Util.applyDefaults({sld:{StyledLayerDescriptor:function(a,b){b.version=a.getAttribute("version");this.readChildNodes(a,b)},Name:function(a,b){b.name=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b.description=this.getChildValue(a)},NamedLayer:function(a,b){var c=
2584 {userStyles:[],namedStyles:[]};this.readChildNodes(a,c);for(var d=0,e=c.userStyles.length;d<e;++d)c.userStyles[d].layerName=c.name;OpenLayers.Util.isArray(b.namedLayers)?b.namedLayers.push(c):b.namedLayers[c.name]=c},NamedStyle:function(a,b){b.namedStyles.push(this.getChildName(a.firstChild))},UserStyle:function(a,b){var c={defaultsPerSymbolizer:!0,rules:[]};this.featureTypeCounter=-1;this.readChildNodes(a,c);this.multipleSymbolizers?(delete c.defaultsPerSymbolizer,c=new OpenLayers.Style2(c)):c=new OpenLayers.Style(this.defaultSymbolizer,
2585 c);b.userStyles.push(c)},IsDefault:function(a,b){"1"==this.getChildValue(a)&&(b.isDefault=!0)},FeatureTypeStyle:function(a,b){++this.featureTypeCounter;var c={rules:this.multipleSymbolizers?b.rules:[]};this.readChildNodes(a,c);this.multipleSymbolizers||(b.rules=c.rules)},Rule:function(a,b){var c;this.multipleSymbolizers&&(c={symbolizers:[]});c=new OpenLayers.Rule(c);this.readChildNodes(a,c);b.rules.push(c)},ElseFilter:function(a,b){b.elseFilter=!0},MinScaleDenominator:function(a,b){b.minScaleDenominator=
2586 parseFloat(this.getChildValue(a))},MaxScaleDenominator:function(a,b){b.maxScaleDenominator=parseFloat(this.getChildValue(a))},TextSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Text(c))):b.symbolizer.Text=OpenLayers.Util.applyDefaults(c,b.symbolizer.Text)},LabelPlacement:function(a,b){this.readChildNodes(a,b)},PointPlacement:function(a,b){var c={};this.readChildNodes(a,c);c.labelRotation=
2587 c.rotation;delete c.rotation;var d,e=b.labelAnchorPointX,f=b.labelAnchorPointY;e<=1/3?d="l":e>1/3&&e<2/3?d="c":e>=2/3&&(d="r");f<=1/3?d+="b":f>1/3&&f<2/3?d+="m":f>=2/3&&(d+="t");c.labelAlign=d;OpenLayers.Util.applyDefaults(b,c)},AnchorPoint:function(a,b){this.readChildNodes(a,b)},AnchorPointX:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelAnchorPointX=c)},AnchorPointY:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelAnchorPointY=c)},Displacement:function(a,
2588 b){this.readChildNodes(a,b)},DisplacementX:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelXOffset=c)},DisplacementY:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelYOffset=c)},LinePlacement:function(a,b){this.readChildNodes(a,b)},PerpendicularOffset:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.labelPerpendicularOffset=c)},Label:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.label=c)},Font:function(a,b){this.readChildNodes(a,
2589 b)},Halo:function(a,b){var c={};this.readChildNodes(a,c);b.haloRadius=c.haloRadius;b.haloColor=c.fillColor;b.haloOpacity=c.fillOpacity},Radius:function(a,b){var c=this.readers.ogc._expression.call(this,a);null!=c&&(b.haloRadius=c)},RasterSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Raster(c))):b.symbolizer.Raster=OpenLayers.Util.applyDefaults(c,b.symbolizer.Raster)},Geometry:function(a,
2590 b){b.geometry={};this.readChildNodes(a,b.geometry)},ColorMap:function(a,b){b.colorMap=[];this.readChildNodes(a,b.colorMap)},ColorMapEntry:function(a,b){var c=a.getAttribute("quantity"),d=a.getAttribute("opacity");b.push({color:a.getAttribute("color"),quantity:null!==c?parseFloat(c):void 0,label:a.getAttribute("label")||void 0,opacity:null!==d?parseFloat(d):void 0})},LineSymbolizer:function(a,b){var c={};this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Line(c))):
2591 b.symbolizer.Line=OpenLayers.Util.applyDefaults(c,b.symbolizer.Line)},PolygonSymbolizer:function(a,b){var c={fill:!1,stroke:!1};this.multipleSymbolizers||(c=b.symbolizer.Polygon||c);this.readChildNodes(a,c);this.multipleSymbolizers?(c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Polygon(c))):b.symbolizer.Polygon=c},PointSymbolizer:function(a,b){var c={fill:!1,stroke:!1,graphic:!1};this.multipleSymbolizers||(c=b.symbolizer.Point||c);this.readChildNodes(a,c);this.multipleSymbolizers?
2592 (c.zIndex=this.featureTypeCounter,b.symbolizers.push(new OpenLayers.Symbolizer.Point(c))):b.symbolizer.Point=c},Stroke:function(a,b){b.stroke=!0;this.readChildNodes(a,b)},Fill:function(a,b){b.fill=!0;this.readChildNodes(a,b)},CssParameter:function(a,b){var c=a.getAttribute("name"),d=this.cssMap[c];b.label&&("fill"===c?d="fontColor":"fill-opacity"===c&&(d="fontOpacity"));d&&(c=this.readers.ogc._expression.call(this,a))&&(b[d]=c)},Graphic:function(a,b){b.graphic=!0;var c={};this.readChildNodes(a,c);
2593 for(var d="stroke strokeColor strokeWidth strokeOpacity strokeLinecap fill fillColor fillOpacity graphicName rotation graphicFormat".split(" "),e,f,g=0,h=d.length;g<h;++g)e=d[g],f=c[e],void 0!=f&&(b[e]=f);void 0!=c.opacity&&(b.graphicOpacity=c.opacity);void 0!=c.size&&(isNaN(c.size/2)?b.graphicWidth=c.size:b.pointRadius=c.size/2);void 0!=c.href&&(b.externalGraphic=c.href);void 0!=c.rotation&&(b.rotation=c.rotation)},ExternalGraphic:function(a,b){this.readChildNodes(a,b)},Mark:function(a,b){this.readChildNodes(a,
2594 b)},WellKnownName:function(a,b){b.graphicName=this.getChildValue(a)},Opacity:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.opacity=c)},Size:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.size=c)},Rotation:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.rotation=c)},OnlineResource:function(a,b){b.href=this.getAttributeNS(a,this.namespaces.xlink,"href")},Format:function(a,b){b.graphicFormat=this.getChildValue(a)}}},OpenLayers.Format.Filter.v1_0_0.prototype.readers),
2595 cssMap:{stroke:"strokeColor","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","stroke-linecap":"strokeLinecap","stroke-dasharray":"strokeDashstyle",fill:"fillColor","fill-opacity":"fillOpacity","font-family":"fontFamily","font-size":"fontSize","font-weight":"fontWeight","font-style":"fontStyle"},getCssProperty:function(a){var b=null,c;for(c in this.cssMap)if(this.cssMap[c]==a){b=c;break}return b},getGraphicFormat:function(a){var b,c;for(c in this.graphicFormats)if(this.graphicFormats[c].test(a)){b=
2596 c;break}return b||this.defaultGraphicFormat},defaultGraphicFormat:"image/png",graphicFormats:{"image/jpeg":/\.jpe?g$/i,"image/gif":/\.gif$/i,"image/png":/\.png$/i},write:function(a){return this.writers.sld.StyledLayerDescriptor.apply(this,[a])},writers:OpenLayers.Util.applyDefaults({sld:{_OGCExpression:function(a,b){var c=this.createElementNSPlus(a),d="string"==typeof b?b.split("${"):[b];c.appendChild(this.createTextNode(d[0]));for(var e,f,g=1,h=d.length;g<h;g++)e=d[g],f=e.indexOf("}"),0<f?(this.writeNode("ogc:PropertyName",
2597 {property:e.substring(0,f)},c),c.appendChild(this.createTextNode(e.substring(++f)))):c.appendChild(this.createTextNode("${"+e));return c},StyledLayerDescriptor:function(a){var b=this.createElementNSPlus("sld:StyledLayerDescriptor",{attributes:{version:this.VERSION,"xsi:schemaLocation":this.schemaLocation}});b.setAttribute("xmlns:ogc",this.namespaces.ogc);b.setAttribute("xmlns:gml",this.namespaces.gml);a.name&&this.writeNode("Name",a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&
2598 this.writeNode("Abstract",a.description,b);if(OpenLayers.Util.isArray(a.namedLayers))for(var c=0,d=a.namedLayers.length;c<d;++c)this.writeNode("NamedLayer",a.namedLayers[c],b);else for(c in a.namedLayers)this.writeNode("NamedLayer",a.namedLayers[c],b);return b},Name:function(a){return this.createElementNSPlus("sld:Name",{value:a})},Title:function(a){return this.createElementNSPlus("sld:Title",{value:a})},Abstract:function(a){return this.createElementNSPlus("sld:Abstract",{value:a})},NamedLayer:function(a){var b=
2599 this.createElementNSPlus("sld:NamedLayer");this.writeNode("Name",a.name,b);if(a.namedStyles)for(var c=0,d=a.namedStyles.length;c<d;++c)this.writeNode("NamedStyle",a.namedStyles[c],b);if(a.userStyles){c=0;for(d=a.userStyles.length;c<d;++c)this.writeNode("UserStyle",a.userStyles[c],b)}return b},NamedStyle:function(a){var b=this.createElementNSPlus("sld:NamedStyle");this.writeNode("Name",a,b);return b},UserStyle:function(a){var b=this.createElementNSPlus("sld:UserStyle");a.name&&this.writeNode("Name",
2600 a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&this.writeNode("Abstract",a.description,b);a.isDefault&&this.writeNode("IsDefault",a.isDefault,b);if(this.multipleSymbolizers&&a.rules){for(var c={"0":[]},d=[0],e,f,g,h,i,j=0,k=a.rules.length;j<k;++j)if(e=a.rules[j],e.symbolizers){f={};for(var l=0,m=e.symbolizers.length;l<m;++l)g=e.symbolizers[l],h=g.zIndex,h in f||(i=e.clone(),i.symbolizers=[],f[h]=i),f[h].symbolizers.push(g.clone());for(h in f)h in c||(d.push(h),c[h]=[]),c[h].push(f[h])}else c[0].push(e.clone());
2601 d.sort();j=0;for(k=d.length;j<k;++j)e=c[d[j]],0<e.length&&(i=a.clone(),i.rules=c[d[j]],this.writeNode("FeatureTypeStyle",i,b))}else this.writeNode("FeatureTypeStyle",a,b);return b},IsDefault:function(a){return this.createElementNSPlus("sld:IsDefault",{value:a?"1":"0"})},FeatureTypeStyle:function(a){for(var b=this.createElementNSPlus("sld:FeatureTypeStyle"),c=0,d=a.rules.length;c<d;++c)this.writeNode("Rule",a.rules[c],b);return b},Rule:function(a){var b=this.createElementNSPlus("sld:Rule");a.name&&
2602 this.writeNode("Name",a.name,b);a.title&&this.writeNode("Title",a.title,b);a.description&&this.writeNode("Abstract",a.description,b);a.elseFilter?this.writeNode("ElseFilter",null,b):a.filter&&this.writeNode("ogc:Filter",a.filter,b);void 0!=a.minScaleDenominator&&this.writeNode("MinScaleDenominator",a.minScaleDenominator,b);void 0!=a.maxScaleDenominator&&this.writeNode("MaxScaleDenominator",a.maxScaleDenominator,b);var c,d;if(this.multipleSymbolizers&&a.symbolizers)for(var e=0,f=a.symbolizers.length;e<
2603 f;++e)d=a.symbolizers[e],c=d.CLASS_NAME.split(".").pop(),this.writeNode(c+"Symbolizer",d,b);else for(var f=OpenLayers.Style.SYMBOLIZER_PREFIXES,e=0,g=f.length;e<g;++e)c=f[e],(d=a.symbolizer[c])&&this.writeNode(c+"Symbolizer",d,b);return b},ElseFilter:function(){return this.createElementNSPlus("sld:ElseFilter")},MinScaleDenominator:function(a){return this.createElementNSPlus("sld:MinScaleDenominator",{value:a})},MaxScaleDenominator:function(a){return this.createElementNSPlus("sld:MaxScaleDenominator",
2604 {value:a})},LineSymbolizer:function(a){var b=this.createElementNSPlus("sld:LineSymbolizer");this.writeNode("Stroke",a,b);return b},Stroke:function(a){var b=this.createElementNSPlus("sld:Stroke");void 0!=a.strokeColor&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeColor"},b);void 0!=a.strokeOpacity&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeOpacity"},b);void 0!=a.strokeWidth&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeWidth"},b);void 0!=a.strokeDashstyle&&"solid"!==
2605 a.strokeDashstyle&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeDashstyle"},b);void 0!=a.strokeLinecap&&this.writeNode("CssParameter",{symbolizer:a,key:"strokeLinecap"},b);return b},CssParameter:function(a){return this.createElementNSPlus("sld:CssParameter",{attributes:{name:this.getCssProperty(a.key)},value:a.symbolizer[a.key]})},TextSymbolizer:function(a){var b=this.createElementNSPlus("sld:TextSymbolizer");null!=a.label&&this.writeNode("Label",a.label,b);(null!=a.fontFamily||null!=a.fontSize||
2606 null!=a.fontWeight||null!=a.fontStyle)&&this.writeNode("Font",a,b);(null!=a.labelAnchorPointX||null!=a.labelAnchorPointY||null!=a.labelAlign||null!=a.labelXOffset||null!=a.labelYOffset||null!=a.labelRotation||null!=a.labelPerpendicularOffset)&&this.writeNode("LabelPlacement",a,b);(null!=a.haloRadius||null!=a.haloColor||null!=a.haloOpacity)&&this.writeNode("Halo",a,b);(null!=a.fontColor||null!=a.fontOpacity)&&this.writeNode("Fill",{fillColor:a.fontColor,fillOpacity:a.fontOpacity},b);return b},LabelPlacement:function(a){var b=
2607 this.createElementNSPlus("sld:LabelPlacement");(null!=a.labelAnchorPointX||null!=a.labelAnchorPointY||null!=a.labelAlign||null!=a.labelXOffset||null!=a.labelYOffset||null!=a.labelRotation)&&null==a.labelPerpendicularOffset&&this.writeNode("PointPlacement",a,b);null!=a.labelPerpendicularOffset&&this.writeNode("LinePlacement",a,b);return b},LinePlacement:function(a){var b=this.createElementNSPlus("sld:LinePlacement");this.writeNode("PerpendicularOffset",a.labelPerpendicularOffset,b);return b},PerpendicularOffset:function(a){return this.createElementNSPlus("sld:PerpendicularOffset",
2608 {value:a})},PointPlacement:function(a){var b=this.createElementNSPlus("sld:PointPlacement");(null!=a.labelAnchorPointX||null!=a.labelAnchorPointY||null!=a.labelAlign)&&this.writeNode("AnchorPoint",a,b);(null!=a.labelXOffset||null!=a.labelYOffset)&&this.writeNode("Displacement",a,b);null!=a.labelRotation&&this.writeNode("Rotation",a.labelRotation,b);return b},AnchorPoint:function(a){var b=this.createElementNSPlus("sld:AnchorPoint"),c=a.labelAnchorPointX,d=a.labelAnchorPointY;null!=c&&this.writeNode("AnchorPointX",
2609 c,b);null!=d&&this.writeNode("AnchorPointY",d,b);if(null==c&&null==d){var e=a.labelAlign.substr(0,1),a=a.labelAlign.substr(1,1);"l"===e?c=0:"c"===e?c=0.5:"r"===e&&(c=1);"b"===a?d=0:"m"===a?d=0.5:"t"===a&&(d=1);this.writeNode("AnchorPointX",c,b);this.writeNode("AnchorPointY",d,b)}return b},AnchorPointX:function(a){return this.createElementNSPlus("sld:AnchorPointX",{value:a})},AnchorPointY:function(a){return this.createElementNSPlus("sld:AnchorPointY",{value:a})},Displacement:function(a){var b=this.createElementNSPlus("sld:Displacement");
2610 null!=a.labelXOffset&&this.writeNode("DisplacementX",a.labelXOffset,b);null!=a.labelYOffset&&this.writeNode("DisplacementY",a.labelYOffset,b);return b},DisplacementX:function(a){return this.createElementNSPlus("sld:DisplacementX",{value:a})},DisplacementY:function(a){return this.createElementNSPlus("sld:DisplacementY",{value:a})},Font:function(a){var b=this.createElementNSPlus("sld:Font");a.fontFamily&&this.writeNode("CssParameter",{symbolizer:a,key:"fontFamily"},b);a.fontSize&&this.writeNode("CssParameter",
2611 {symbolizer:a,key:"fontSize"},b);a.fontWeight&&this.writeNode("CssParameter",{symbolizer:a,key:"fontWeight"},b);a.fontStyle&&this.writeNode("CssParameter",{symbolizer:a,key:"fontStyle"},b);return b},Label:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Label",a)},Halo:function(a){var b=this.createElementNSPlus("sld:Halo");a.haloRadius&&this.writeNode("Radius",a.haloRadius,b);(a.haloColor||a.haloOpacity)&&this.writeNode("Fill",{fillColor:a.haloColor,fillOpacity:a.haloOpacity},b);
2612 return b},Radius:function(a){return this.createElementNSPlus("sld:Radius",{value:a})},RasterSymbolizer:function(a){var b=this.createElementNSPlus("sld:RasterSymbolizer");a.geometry&&this.writeNode("Geometry",a.geometry,b);a.opacity&&this.writeNode("Opacity",a.opacity,b);a.colorMap&&this.writeNode("ColorMap",a.colorMap,b);return b},Geometry:function(a){var b=this.createElementNSPlus("sld:Geometry");a.property&&this.writeNode("ogc:PropertyName",a,b);return b},ColorMap:function(a){for(var b=this.createElementNSPlus("sld:ColorMap"),
2613 c=0,d=a.length;c<d;++c)this.writeNode("ColorMapEntry",a[c],b);return b},ColorMapEntry:function(a){var b=this.createElementNSPlus("sld:ColorMapEntry");b.setAttribute("color",a.color);void 0!==a.opacity&&b.setAttribute("opacity",parseFloat(a.opacity));void 0!==a.quantity&&b.setAttribute("quantity",parseFloat(a.quantity));void 0!==a.label&&b.setAttribute("label",a.label);return b},PolygonSymbolizer:function(a){var b=this.createElementNSPlus("sld:PolygonSymbolizer");!1!==a.fill&&this.writeNode("Fill",
2614 a,b);!1!==a.stroke&&this.writeNode("Stroke",a,b);return b},Fill:function(a){var b=this.createElementNSPlus("sld:Fill");a.fillColor&&this.writeNode("CssParameter",{symbolizer:a,key:"fillColor"},b);null!=a.fillOpacity&&this.writeNode("CssParameter",{symbolizer:a,key:"fillOpacity"},b);return b},PointSymbolizer:function(a){var b=this.createElementNSPlus("sld:PointSymbolizer");this.writeNode("Graphic",a,b);return b},Graphic:function(a){var b=this.createElementNSPlus("sld:Graphic");void 0!=a.externalGraphic?
2615 this.writeNode("ExternalGraphic",a,b):this.writeNode("Mark",a,b);void 0!=a.graphicOpacity&&this.writeNode("Opacity",a.graphicOpacity,b);void 0!=a.pointRadius?this.writeNode("Size",2*a.pointRadius,b):void 0!=a.graphicWidth&&this.writeNode("Size",a.graphicWidth,b);void 0!=a.rotation&&this.writeNode("Rotation",a.rotation,b);return b},ExternalGraphic:function(a){var b=this.createElementNSPlus("sld:ExternalGraphic");this.writeNode("OnlineResource",a.externalGraphic,b);this.writeNode("Format",a.graphicFormat||
2616 this.getGraphicFormat(a.externalGraphic),b);return b},Mark:function(a){var b=this.createElementNSPlus("sld:Mark");a.graphicName&&this.writeNode("WellKnownName",a.graphicName,b);!1!==a.fill&&this.writeNode("Fill",a,b);!1!==a.stroke&&this.writeNode("Stroke",a,b);return b},WellKnownName:function(a){return this.createElementNSPlus("sld:WellKnownName",{value:a})},Opacity:function(a){return this.createElementNSPlus("sld:Opacity",{value:a})},Size:function(a){return this.writers.sld._OGCExpression.call(this,
2617 "sld:Size",a)},Rotation:function(a){return this.createElementNSPlus("sld:Rotation",{value:a})},OnlineResource:function(a){return this.createElementNSPlus("sld:OnlineResource",{attributes:{"xlink:type":"simple","xlink:href":a}})},Format:function(a){return this.createElementNSPlus("sld:Format",{value:a})}}},OpenLayers.Format.Filter.v1_0_0.prototype.writers),CLASS_NAME:"OpenLayers.Format.SLD.v1"});OpenLayers.Layer.WMS=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{service:"WMS",version:"1.1.1",request:"GetMap",styles:"",format:"image/jpeg"},isBaseLayer:!0,encodeBBOX:!1,noMagic:!1,yx:{},initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);1.3<=parseFloat(c.VERSION)&&!c.EXCEPTIONS&&(c.EXCEPTIONS="INIMAGE");e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));
2618 if(!this.noMagic&&this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()){if(null==d||!d.isBaseLayer)this.isBaseLayer=!1;"image/jpeg"==this.params.FORMAT&&(this.params.FORMAT=OpenLayers.Util.alphaHack()?"image/gif":"image/png")}},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMS(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},reverseAxisOrder:function(){var a=this.projection.getCode();return 1.3<=parseFloat(this.params.VERSION)&&
2619 !(!this.yx[a]&&!OpenLayers.Projection.defaults[a].yx)},getURL:function(a){var a=this.adjustBounds(a),b=this.getImageSize(),c={},d=this.reverseAxisOrder();c.BBOX=this.encodeBBOX?a.toBBOX(null,d):a.toArray(d);c.WIDTH=b.w;c.HEIGHT=b.h;return this.getFullRequestString(c)},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},getFullRequestString:function(a,b){var c=this.map.getProjectionObject(),c=this.projection&&this.projection.equals(c)?
2620 this.projection.getCode():c.getCode(),c="none"==c?null:c;1.3<=parseFloat(this.params.VERSION)?this.params.CRS=c:this.params.SRS=c;"boolean"==typeof this.params.TRANSPARENT&&(a.TRANSPARENT=this.params.TRANSPARENT?"TRUE":"FALSE");return OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,arguments)},CLASS_NAME:"OpenLayers.Layer.WMS"});OpenLayers.Format.WMC.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.1.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.1.0/context.xsd",initialize:function(a){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[a])},read_sld_MinScaleDenominator:function(a,b){var c=parseFloat(this.getChildValue(b));0<c&&(a.maxScale=c)},read_sld_MaxScaleDenominator:function(a,b){a.minScale=parseFloat(this.getChildValue(b))},read_wmc_SRS:function(a,b){"srs"in
2621 a||(a.srs={});a.srs[this.getChildValue(b)]=!0},write_wmc_Layer:function(a){var b=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,[a]);if(a.maxScale){var c=this.createElementNS(this.namespaces.sld,"sld:MinScaleDenominator");c.appendChild(this.createTextNode(a.maxScale.toPrecision(16)));b.appendChild(c)}a.minScale&&(c=this.createElementNS(this.namespaces.sld,"sld:MaxScaleDenominator"),c.appendChild(this.createTextNode(a.minScale.toPrecision(16))),b.appendChild(c));if(a.srs)for(var d in a.srs)b.appendChild(this.createElementDefaultNS("SRS",
2622 d));b.appendChild(this.write_wmc_FormatList(a));b.appendChild(this.write_wmc_StyleList(a));a.dimensions&&b.appendChild(this.write_wmc_DimensionList(a));b.appendChild(this.write_wmc_LayerExtension(a));return b},CLASS_NAME:"OpenLayers.Format.WMC.v1_1_0"});OpenLayers.Format.XLS=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.0",stringifyOutput:!0,CLASS_NAME:"OpenLayers.Format.XLS"});OpenLayers.Format.XLS.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xls:"http://www.opengis.net/xls",gml:"http://www.opengis.net/gml",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},xy:!0,defaultPrefix:"xls",schemaLocation:null,read:function(a,b){OpenLayers.Util.applyDefaults(b,this.options);var c={};this.readChildNodes(a,c);return c},readers:{xls:{XLS:function(a,b){b.version=a.getAttribute("version");
2623 this.readChildNodes(a,b)},Response:function(a,b){this.readChildNodes(a,b)},GeocodeResponse:function(a,b){b.responseLists=[];this.readChildNodes(a,b)},GeocodeResponseList:function(a,b){var c={features:[],numberOfGeocodedAddresses:parseInt(a.getAttribute("numberOfGeocodedAddresses"))};b.responseLists.push(c);this.readChildNodes(a,c)},GeocodedAddress:function(a,b){var c=new OpenLayers.Feature.Vector;b.features.push(c);this.readChildNodes(a,c);c.geometry=c.components[0]},GeocodeMatchCode:function(a,b){b.attributes.matchCode=
2624 {accuracy:parseFloat(a.getAttribute("accuracy")),matchType:a.getAttribute("matchType")}},Address:function(a,b){var c={countryCode:a.getAttribute("countryCode"),addressee:a.getAttribute("addressee"),street:[],place:[]};b.attributes.address=c;this.readChildNodes(a,c)},freeFormAddress:function(a,b){b.freeFormAddress=this.getChildValue(a)},StreetAddress:function(a,b){this.readChildNodes(a,b)},Building:function(a,b){b.building={number:a.getAttribute("number"),subdivision:a.getAttribute("subdivision"),
2625 buildingName:a.getAttribute("buildingName")}},Street:function(a,b){b.street.push(this.getChildValue(a))},Place:function(a,b){b.place[a.getAttribute("type")]=this.getChildValue(a)},PostalCode:function(a,b){b.postalCode=this.getChildValue(a)}},gml:OpenLayers.Format.GML.v3.prototype.readers.gml},write:function(a){return this.writers.xls.XLS.apply(this,[a])},writers:{xls:{XLS:function(a){var b=this.createElementNSPlus("xls:XLS",{attributes:{version:this.VERSION,"xsi:schemaLocation":this.schemaLocation}});
2626 this.writeNode("RequestHeader",a.header,b);this.writeNode("Request",a,b);return b},RequestHeader:function(){return this.createElementNSPlus("xls:RequestHeader")},Request:function(a){var b=this.createElementNSPlus("xls:Request",{attributes:{methodName:"GeocodeRequest",requestID:a.requestID||"",version:this.VERSION}});this.writeNode("GeocodeRequest",a.addresses,b);return b},GeocodeRequest:function(a){for(var b=this.createElementNSPlus("xls:GeocodeRequest"),c=0,d=a.length;c<d;c++)this.writeNode("Address",
2627 a[c],b);return b},Address:function(a){var b=this.createElementNSPlus("xls:Address",{attributes:{countryCode:a.countryCode}});a.freeFormAddress?this.writeNode("freeFormAddress",a.freeFormAddress,b):(a.street&&this.writeNode("StreetAddress",a,b),a.municipality&&this.writeNode("Municipality",a.municipality,b),a.countrySubdivision&&this.writeNode("CountrySubdivision",a.countrySubdivision,b),a.postalCode&&this.writeNode("PostalCode",a.postalCode,b));return b},freeFormAddress:function(a){return this.createElementNSPlus("freeFormAddress",
2628 {value:a})},StreetAddress:function(a){var b=this.createElementNSPlus("xls:StreetAddress");a.building&&this.writeNode(b,"Building",a.building);a=a.street;OpenLayers.Util.isArray(a)||(a=[a]);for(var c=0,d=a.length;c<d;c++)this.writeNode("Street",a[c],b);return b},Building:function(a){return this.createElementNSPlus("xls:Building",{attributes:{number:a.number,subdivision:a.subdivision,buildingName:a.buildingName}})},Street:function(a){return this.createElementNSPlus("xls:Street",{value:a})},Municipality:function(a){return this.createElementNSPlus("xls:Place",
2629 {attributes:{type:"Municipality"},value:a})},CountrySubdivision:function(a){return this.createElementNSPlus("xls:Place",{attributes:{type:"CountrySubdivision"},value:a})},PostalCode:function(a){return this.createElementNSPlus("xls:PostalCode",{value:a})}}},CLASS_NAME:"OpenLayers.Format.XLS.v1"});OpenLayers.Format.XLS.v1_1_0=OpenLayers.Class(OpenLayers.Format.XLS.v1,{VERSION:"1.1",schemaLocation:"http://www.opengis.net/xls http://schemas.opengis.net/ols/1.1.0/LocationUtilityService.xsd",CLASS_NAME:"OpenLayers.Format.XLS.v1_1_0"});OpenLayers.Format.XLS.v1_1=OpenLayers.Format.XLS.v1_1_0;OpenLayers.Renderer.SVG=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"http://www.w3.org/2000/svg",xlinkns:"http://www.w3.org/1999/xlink",MAX_PIXEL:15E3,translationParameters:null,symbolMetrics:null,initialize:function(a){this.supported()&&(OpenLayers.Renderer.Elements.prototype.initialize.apply(this,arguments),this.translationParameters={x:0,y:0},this.symbolMetrics={})},supported:function(){return document.implementation&&(document.implementation.hasFeature("org.w3c.svg","1.0")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#SVG",
2630 "1.1")||document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure","1.1"))},inValidRange:function(a,b,c){a+=c?0:this.translationParameters.x;b+=c?0:this.translationParameters.y;return a>=-this.MAX_PIXEL&&a<=this.MAX_PIXEL&&b>=-this.MAX_PIXEL&&b<=this.MAX_PIXEL},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=-a.left/d,d=a.top/d;if(b)return this.left=e,this.top=d,this.rendererRoot.setAttributeNS(null,
2631 "viewBox","0 0 "+this.size.w+" "+this.size.h),this.translate(this.xOffset,0),!0;(e=this.translate(e-this.left+this.xOffset,d-this.top))||this.setExtent(a,!0);return c&&e},translate:function(a,b){if(this.inValidRange(a,b,!0)){var c="";if(a||b)c="translate("+a+","+b+")";this.root.setAttributeNS(null,"transform",c);this.translationParameters={x:a,y:b};return!0}return!1},setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);this.rendererRoot.setAttributeNS(null,"width",this.size.w);
2632 this.rendererRoot.setAttributeNS(null,"height",this.size.h)},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"image":this.isComplexSymbol(b.graphicName)?"svg":"circle";break;case "OpenLayers.Geometry.Rectangle":c="rect";break;case "OpenLayers.Geometry.LineString":c="polyline";break;case "OpenLayers.Geometry.LinearRing":c="polygon";break;case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c="path"}return c},setStyle:function(a,
2633 b,c){var b=b||a._style,c=c||a._options,d=parseFloat(a.getAttributeNS(null,"r")),e=1,f;if("OpenLayers.Geometry.Point"==a._geometryClass&&d){a.style.visibility="";if(!1===b.graphic)a.style.visibility="hidden";else if(b.externalGraphic){f=this.getPosition(a);b.graphicTitle&&(a.setAttributeNS(null,"title",b.graphicTitle),d=a.getElementsByTagName("title"),0<d.length?d[0].firstChild.textContent=b.graphicTitle:(d=this.nodeFactory(null,"title"),d.textContent=b.graphicTitle,a.appendChild(d)));b.graphicWidth&&
2634 b.graphicHeight&&a.setAttributeNS(null,"preserveAspectRatio","none");var d=b.graphicWidth||b.graphicHeight,g=b.graphicHeight||b.graphicWidth,d=d?d:2*b.pointRadius,g=g?g:2*b.pointRadius,h=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*g),i=b.graphicOpacity||b.fillOpacity;a.setAttributeNS(null,"x",(f.x+(void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*d))).toFixed());a.setAttributeNS(null,"y",(f.y+h).toFixed());a.setAttributeNS(null,"width",d);a.setAttributeNS(null,"height",g);a.setAttributeNS(this.xlinkns,
2635 "href",b.externalGraphic);a.setAttributeNS(null,"style","opacity: "+i);a.onclick=OpenLayers.Renderer.SVG.preventDefault}else if(this.isComplexSymbol(b.graphicName)){var d=3*b.pointRadius,g=2*d,j=this.importSymbol(b.graphicName);f=this.getPosition(a);e=3*this.symbolMetrics[j.id][0]/g;h=a.parentNode;i=a.nextSibling;h&&h.removeChild(a);a.firstChild&&a.removeChild(a.firstChild);a.appendChild(j.firstChild.cloneNode(!0));a.setAttributeNS(null,"viewBox",j.getAttributeNS(null,"viewBox"));a.setAttributeNS(null,
2636 "width",g);a.setAttributeNS(null,"height",g);a.setAttributeNS(null,"x",f.x-d);a.setAttributeNS(null,"y",f.y-d);i?h.insertBefore(a,i):h&&h.appendChild(a)}else a.setAttributeNS(null,"r",b.pointRadius);d=b.rotation;if((void 0!==d||void 0!==a._rotation)&&f)a._rotation=d,d|=0,"svg"!==a.nodeName?a.setAttributeNS(null,"transform","rotate("+d+" "+f.x+" "+f.y+")"):(f=this.symbolMetrics[j.id],a.firstChild.setAttributeNS(null,"transform","rotate("+d+" "+f[1]+" "+f[2]+")"))}c.isFilled?(a.setAttributeNS(null,
2637 "fill",b.fillColor),a.setAttributeNS(null,"fill-opacity",b.fillOpacity)):a.setAttributeNS(null,"fill","none");c.isStroked?(a.setAttributeNS(null,"stroke",b.strokeColor),a.setAttributeNS(null,"stroke-opacity",b.strokeOpacity),a.setAttributeNS(null,"stroke-width",b.strokeWidth*e),a.setAttributeNS(null,"stroke-linecap",b.strokeLinecap||"round"),a.setAttributeNS(null,"stroke-linejoin","round"),b.strokeDashstyle&&a.setAttributeNS(null,"stroke-dasharray",this.dashStyle(b,e))):a.setAttributeNS(null,"stroke",
2638 "none");b.pointerEvents&&a.setAttributeNS(null,"pointer-events",b.pointerEvents);null!=b.cursor&&a.setAttributeNS(null,"cursor",b.cursor);return a},dashStyle:function(a,b){var c=a.strokeWidth*b,d=a.strokeDashstyle;switch(d){case "solid":return"none";case "dot":return[1,4*c].join();case "dash":return[4*c,4*c].join();case "dashdot":return[4*c,4*c,1,4*c].join();case "longdash":return[8*c,4*c].join();case "longdashdot":return[8*c,4*c,1,4*c].join();default:return OpenLayers.String.trim(d).replace(/\s+/g,
2639 ",")}},createNode:function(a,b){var c=document.createElementNS(this.xmlns,a);b&&c.setAttributeNS(null,"id",b);return c},nodeTypeCompare:function(a,b){return b==a.nodeName},createRenderRoot:function(){var a=this.nodeFactory(this.container.id+"_svgRoot","svg");a.style.display="block";return a},createRoot:function(a){return this.nodeFactory(this.container.id+a,"g")},createDefs:function(){var a=this.nodeFactory(this.container.id+"_defs","defs");this.rendererRoot.appendChild(a);return a},drawPoint:function(a,
2640 b){return this.drawCircle(a,b,1)},drawCircle:function(a,b,c){var d=this.getResolution(),e=(b.x-this.featureDx)/d+this.left,b=this.top-b.y/d;return this.inValidRange(e,b)?(a.setAttributeNS(null,"cx",e),a.setAttributeNS(null,"cy",b),a.setAttributeNS(null,"r",c),a):!1},drawLineString:function(a,b){var c=this.getComponentsString(b.components);return c.path?(a.setAttributeNS(null,"points",c.path),c.complete?a:null):!1},drawLinearRing:function(a,b){var c=this.getComponentsString(b.components);return c.path?
2641 (a.setAttributeNS(null,"points",c.path),c.complete?a:null):!1},drawPolygon:function(a,b){for(var c="",d=!0,e=!0,f,g,h=0,i=b.components.length;h<i;h++)c+=" M",f=this.getComponentsString(b.components[h].components," "),(g=f.path)?(c+=" "+g,e=f.complete&&e):d=!1;return d?(a.setAttributeNS(null,"d",c+" z"),a.setAttributeNS(null,"fill-rule","evenodd"),e?a:null):!1},drawRectangle:function(a,b){var c=this.getResolution(),d=(b.x-this.featureDx)/c+this.left,e=this.top-b.y/c;return this.inValidRange(d,e)?(a.setAttributeNS(null,
2642 "x",d),a.setAttributeNS(null,"y",e),a.setAttributeNS(null,"width",b.width/c),a.setAttributeNS(null,"height",b.height/c),a):!1},drawText:function(a,b,c){var d=!!b.labelOutlineWidth;if(d){var e=OpenLayers.Util.extend({},b);e.fontColor=e.labelOutlineColor;e.fontStrokeColor=e.labelOutlineColor;e.fontStrokeWidth=b.labelOutlineWidth;delete e.labelOutlineWidth;this.drawText(a,e,c)}var f=this.getResolution(),e=(c.x-this.featureDx)/f+this.left,g=c.y/f-this.top,d=d?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX,
2643 f=this.nodeFactory(a+d,"text");f.setAttributeNS(null,"x",e);f.setAttributeNS(null,"y",-g);b.fontColor&&f.setAttributeNS(null,"fill",b.fontColor);b.fontStrokeColor&&f.setAttributeNS(null,"stroke",b.fontStrokeColor);b.fontStrokeWidth&&f.setAttributeNS(null,"stroke-width",b.fontStrokeWidth);b.fontOpacity&&f.setAttributeNS(null,"opacity",b.fontOpacity);b.fontFamily&&f.setAttributeNS(null,"font-family",b.fontFamily);b.fontSize&&f.setAttributeNS(null,"font-size",b.fontSize);b.fontWeight&&f.setAttributeNS(null,
2644 "font-weight",b.fontWeight);b.fontStyle&&f.setAttributeNS(null,"font-style",b.fontStyle);!0===b.labelSelect?(f.setAttributeNS(null,"pointer-events","visible"),f._featureId=a):f.setAttributeNS(null,"pointer-events","none");g=b.labelAlign||OpenLayers.Renderer.defaultSymbolizer.labelAlign;f.setAttributeNS(null,"text-anchor",OpenLayers.Renderer.SVG.LABEL_ALIGN[g[0]]||"middle");!0===OpenLayers.IS_GECKO&&f.setAttributeNS(null,"dominant-baseline",OpenLayers.Renderer.SVG.LABEL_ALIGN[g[1]]||"central");for(var h=
2645 b.label.split("\n"),i=h.length;f.childNodes.length>i;)f.removeChild(f.lastChild);for(var j=0;j<i;j++){var k=this.nodeFactory(a+d+"_tspan_"+j,"tspan");!0===b.labelSelect&&(k._featureId=a,k._geometry=c,k._geometryClass=c.CLASS_NAME);!1===OpenLayers.IS_GECKO&&k.setAttributeNS(null,"baseline-shift",OpenLayers.Renderer.SVG.LABEL_VSHIFT[g[1]]||"-35%");k.setAttribute("x",e);if(0==j){var l=OpenLayers.Renderer.SVG.LABEL_VFACTOR[g[1]];null==l&&(l=-0.5);k.setAttribute("dy",l*(i-1)+"em")}else k.setAttribute("dy",
2646 "1em");k.textContent=""===h[j]?" ":h[j];k.parentNode||f.appendChild(k)}f.parentNode||this.textRoot.appendChild(f)},getComponentsString:function(a,b){for(var c=[],d=!0,e=a.length,f=[],g,h=0;h<e;h++)g=a[h],c.push(g),(g=this.getShortString(g))?f.push(g):(0<h&&this.getShortString(a[h-1])&&f.push(this.clipLine(a[h],a[h-1])),h<e-1&&this.getShortString(a[h+1])&&f.push(this.clipLine(a[h],a[h+1])),d=!1);return{path:f.join(b||","),complete:d}},clipLine:function(a,b){if(b.equals(a))return"";var c=this.getResolution(),
2647 d=this.MAX_PIXEL-this.translationParameters.x,e=this.MAX_PIXEL-this.translationParameters.y,f=(b.x-this.featureDx)/c+this.left,g=this.top-b.y/c,h=(a.x-this.featureDx)/c+this.left,c=this.top-a.y/c,i;if(h<-d||h>d)i=(c-g)/(h-f),h=0>h?-d:d,c=g+(h-f)*i;if(c<-e||c>e)i=(h-f)/(c-g),c=0>c?-e:e,h=f+(c-g)*i;return h+","+c},getShortString:function(a){var b=this.getResolution(),c=(a.x-this.featureDx)/b+this.left,a=this.top-a.y/b;return this.inValidRange(c,a)?c+","+a:!1},getPosition:function(a){return{x:parseFloat(a.getAttributeNS(null,
2648 "cx")),y:parseFloat(a.getAttributeNS(null,"cy"))}},importSymbol:function(a){this.defs||(this.defs=this.createDefs());var b=this.container.id+"-"+a,c=document.getElementById(b);if(null!=c)return c;var d=OpenLayers.Renderer.symbol[a];if(!d)throw Error(a+" is not a valid symbol name");var a=this.nodeFactory(b,"symbol"),e=this.nodeFactory(null,"polygon");a.appendChild(e);for(var c=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0),f=[],g,h,i=0;i<d.length;i+=2)g=d[i],h=d[i+1],c.left=Math.min(c.left,
2649 g),c.bottom=Math.min(c.bottom,h),c.right=Math.max(c.right,g),c.top=Math.max(c.top,h),f.push(g,",",h);e.setAttributeNS(null,"points",f.join(" "));d=c.getWidth();e=c.getHeight();a.setAttributeNS(null,"viewBox",[c.left-d,c.bottom-e,3*d,3*e].join(" "));this.symbolMetrics[b]=[Math.max(d,e),c.getCenterLonLat().lon,c.getCenterLonLat().lat];this.defs.appendChild(a);return a},getFeatureIdFromEvent:function(a){var b=OpenLayers.Renderer.Elements.prototype.getFeatureIdFromEvent.apply(this,arguments);b||(b=a.target,
2650 b=b.parentNode&&b!=this.rendererRoot?b.parentNode._featureId:void 0);return b},CLASS_NAME:"OpenLayers.Renderer.SVG"});OpenLayers.Renderer.SVG.LABEL_ALIGN={l:"start",r:"end",b:"bottom",t:"hanging"};OpenLayers.Renderer.SVG.LABEL_VSHIFT={t:"-70%",b:"0"};OpenLayers.Renderer.SVG.LABEL_VFACTOR={t:0,b:-1};OpenLayers.Renderer.SVG.preventDefault=function(a){a.preventDefault&&a.preventDefault()};OpenLayers.Format.SLD.v1_0_0=OpenLayers.Class(OpenLayers.Format.SLD.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sld http://schemas.opengis.net/sld/1.0.0/StyledLayerDescriptor.xsd",CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0"});OpenLayers.Format.OWSContext=OpenLayers.Class(OpenLayers.Format.Context,{defaultVersion:"0.3.1",getVersion:function(a,b){var c=OpenLayers.Format.XML.VersionedOGC.prototype.getVersion.apply(this,arguments);"0.3.0"===c&&(c=this.defaultVersion);return c},toContext:function(a){var b={};"OpenLayers.Map"==a.CLASS_NAME&&(b.bounds=a.getExtent(),b.maxExtent=a.maxExtent,b.projection=a.projection,b.size=a.getSize(),b.layers=a.layers);return b},CLASS_NAME:"OpenLayers.Format.OWSContext"});OpenLayers.Format.OWSContext.v0_3_1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{owc:"http://www.opengis.net/ows-context",gml:"http://www.opengis.net/gml",kml:"http://www.opengis.net/kml/2.2",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",sld:"http://www.opengis.net/sld",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},VERSION:"0.3.1",schemaLocation:"http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd",
2651 defaultPrefix:"owc",extractAttributes:!0,xy:!0,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},featureNS:"http://mapserver.gis.umn.edu/mapserver",featureType:"vector",geometryName:"geometry",nestingLayerLookup:null,initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this)},setNestingPath:function(a){if(a.layersContext)for(var b=0,c=a.layersContext.length;b<c;b++){var d=
2652 a.layersContext[b],e=[],f=a.title||"";a.metadata&&a.metadata.nestingPath&&(e=a.metadata.nestingPath.slice());""!=f&&e.push(f);d.metadata.nestingPath=e;d.layersContext&&this.setNestingPath(d)}},decomposeNestingPath:function(a){var b=[];if(OpenLayers.Util.isArray(a)){for(a=a.slice();0<a.length;)b.push(a.slice()),a.pop();b.reverse()}return b},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,
2653 b);this.setNestingPath({layersContext:b.layersContext});a=[];this.processLayer(a,b);delete b.layersContext;b.layersContext=a;return b},processLayer:function(a,b){if(b.layersContext)for(var c=0,d=b.layersContext.length;c<d;c++){var e=b.layersContext[c];a.push(e);e.layersContext&&this.processLayer(a,e)}},write:function(a,b){this.nestingLayerLookup={};b=b||{};OpenLayers.Util.applyDefaults(b,a);var c=this.writeNode("OWSContext",b);this.nestingLayerLookup=null;this.setAttributeNS(c,this.namespaces.xsi,
2654 "xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,[c])},readers:{kml:{Document:function(a,b){b.features=(new OpenLayers.Format.KML({kmlns:this.namespaces.kml,extractStyles:!0})).read(a)}},owc:{OWSContext:function(a,b){this.readChildNodes(a,b)},General:function(a,b){this.readChildNodes(a,b)},ResourceList:function(a,b){this.readChildNodes(a,b)},Layer:function(a,b){var c={metadata:{},visibility:"1"!=a.getAttribute("hidden"),queryable:"1"==a.getAttribute("queryable"),
2655 opacity:null!=a.getAttribute("opacity")?parseFloat(a.getAttribute("opacity")):null,name:a.getAttribute("name"),categoryLayer:null==a.getAttribute("name"),formats:[],styles:[]};b.layersContext||(b.layersContext=[]);b.layersContext.push(c);this.readChildNodes(a,c)},InlineGeometry:function(a,b){b.features=[];var c=this.getElementsByTagNameNS(a,this.namespaces.gml,"featureMember"),d;1<=c.length&&(d=c[0]);d&&d.firstChild&&(c=d.firstChild.nextSibling?d.firstChild.nextSibling:d.firstChild,this.setNamespace("feature",
2656 c.namespaceURI),this.featureType=c.localName||c.nodeName.split(":").pop(),this.readChildNodes(a,b))},Server:function(a,b){if(!b.service&&!b.version||b.service!=OpenLayers.Format.Context.serviceTypes.WMS)b.service=a.getAttribute("service"),b.version=a.getAttribute("version"),this.readChildNodes(a,b)},Name:function(a,b){b.name=this.getChildValue(a);this.readChildNodes(a,b)},Title:function(a,b){b.title=this.getChildValue(a);this.readChildNodes(a,b)},StyleList:function(a,b){this.readChildNodes(a,b.styles)},
2657 Style:function(a,b){var c={};b.push(c);this.readChildNodes(a,c)},LegendURL:function(a,b){var c={};b.legend=c;this.readChildNodes(a,c)},OnlineResource:function(a,b){b.url=this.getAttributeNS(a,this.namespaces.xlink,"href");this.readChildNodes(a,b)}},ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows,gml:OpenLayers.Format.GML.v2.prototype.readers.gml,sld:OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld,feature:OpenLayers.Format.GML.v2.prototype.readers.feature},writers:{owc:{OWSContext:function(a){var b=
2658 this.createElementNSPlus("OWSContext",{attributes:{version:this.VERSION,id:a.id||OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_")}});this.writeNode("General",a,b);this.writeNode("ResourceList",a,b);return b},General:function(a){var b=this.createElementNSPlus("General");this.writeNode("ows:BoundingBox",a,b);this.writeNode("ows:Title",a.title||"OpenLayers OWSContext",b);return b},ResourceList:function(a){for(var b=this.createElementNSPlus("ResourceList"),c=0,d=a.layers.length;c<d;c++){var e=
2659 a.layers[c],f=this.decomposeNestingPath(e.metadata.nestingPath);this.writeNode("_Layer",{layer:e,subPaths:f},b)}return b},Server:function(a){var b=this.createElementNSPlus("Server",{attributes:{version:a.version,service:a.service}});this.writeNode("OnlineResource",a,b);return b},OnlineResource:function(a){return this.createElementNSPlus("OnlineResource",{attributes:{"xlink:href":a.url}})},InlineGeometry:function(a){var b=this.createElementNSPlus("InlineGeometry");this.writeNode("gml:boundedBy",a.getDataExtent(),
2660 b);for(var c=0,d=a.features.length;c<d;c++)this.writeNode("gml:featureMember",a.features[c],b);return b},StyleList:function(a){for(var b=this.createElementNSPlus("StyleList"),c=0,d=a.length;c<d;c++)this.writeNode("Style",a[c],b);return b},Style:function(a){var b=this.createElementNSPlus("Style");this.writeNode("Name",a,b);this.writeNode("Title",a,b);a.legend&&this.writeNode("LegendURL",a,b);return b},Name:function(a){return this.createElementNSPlus("Name",{value:a.name})},Title:function(a){return this.createElementNSPlus("Title",
2661 {value:a.title})},LegendURL:function(a){var b=this.createElementNSPlus("LegendURL");this.writeNode("OnlineResource",a.legend,b);return b},_WMS:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:a.params.LAYERS,queryable:a.queryable?"1":"0",hidden:a.visibility?"0":"1",opacity:a.hasOwnProperty("opacity")?a.opacity:null}});this.writeNode("ows:Title",a.name,b);this.writeNode("ows:OutputFormat",a.params.FORMAT,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WMS,
2662 version:a.params.VERSION,url:a.url},b);a.metadata.styles&&0<a.metadata.styles.length&&this.writeNode("StyleList",a.metadata.styles,b);return b},_Layer:function(a){var b,c,d;b=a.layer;c=a.subPaths;d=null;0<c.length?(b=c[0].join("/"),c=b.lastIndexOf("/"),d=this.nestingLayerLookup[b],c=0<c?b.substring(c+1,b.length):b,d||(d=this.createElementNSPlus("Layer"),this.writeNode("ows:Title",c,d),this.nestingLayerLookup[b]=d),a.subPaths.shift(),this.writeNode("_Layer",a,d)):(b instanceof OpenLayers.Layer.WMS?
2663 d=this.writeNode("_WMS",b):b instanceof OpenLayers.Layer.Vector&&(b.protocol instanceof OpenLayers.Protocol.WFS.v1?d=this.writeNode("_WFS",b):b.protocol instanceof OpenLayers.Protocol.HTTP?b.protocol.format instanceof OpenLayers.Format.GML?(b.protocol.format.version="2.1.2",d=this.writeNode("_GML",b)):b.protocol.format instanceof OpenLayers.Format.KML&&(b.protocol.format.version="2.2",d=this.writeNode("_KML",b)):(this.setNamespace("feature",this.featureNS),d=this.writeNode("_InlineGeometry",b))),
2664 b.options.maxScale&&this.writeNode("sld:MinScaleDenominator",b.options.maxScale,d),b.options.minScale&&this.writeNode("sld:MaxScaleDenominator",b.options.minScale,d),this.nestingLayerLookup[b.name]=d);return d},_WFS:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:a.protocol.featurePrefix+":"+a.protocol.featureType,hidden:a.visibility?"0":"1"}});this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.WFS,version:a.protocol.version,
2665 url:a.protocol.url},b);return b},_InlineGeometry:function(a){var b=this.createElementNSPlus("Layer",{attributes:{name:this.featureType,hidden:a.visibility?"0":"1"}});this.writeNode("ows:Title",a.name,b);this.writeNode("InlineGeometry",a,b);return b},_GML:function(a){var b=this.createElementNSPlus("Layer");this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.GML,url:a.protocol.url,version:a.protocol.format.version},b);return b},_KML:function(a){var b=
2666 this.createElementNSPlus("Layer");this.writeNode("ows:Title",a.name,b);this.writeNode("Server",{service:OpenLayers.Format.Context.serviceTypes.KML,version:a.protocol.format.version,url:a.protocol.url},b);return b}},gml:OpenLayers.Util.applyDefaults({boundedBy:function(a){var b=this.createElementNSPlus("gml:boundedBy");this.writeNode("gml:Box",a,b);return b}},OpenLayers.Format.GML.v2.prototype.writers.gml),ows:OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows,sld:OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld,
2667 feature:OpenLayers.Format.GML.v2.prototype.writers.feature},CLASS_NAME:"OpenLayers.Format.OWSContext.v0_3_1"});OpenLayers.Control.ScaleLine=OpenLayers.Class(OpenLayers.Control,{maxWidth:100,topOutUnits:"km",topInUnits:"m",bottomOutUnits:"mi",bottomInUnits:"ft",eTop:null,eBottom:null,geodesic:!1,draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.eTop||(this.eTop=document.createElement("div"),this.eTop.className=this.displayClass+"Top",this.div.appendChild(this.eTop),this.eTop.style.visibility=""==this.topOutUnits||""==this.topInUnits?"hidden":"visible",this.eBottom=document.createElement("div"),
2668 this.eBottom.className=this.displayClass+"Bottom",this.div.appendChild(this.eBottom),this.eBottom.style.visibility=""==this.bottomOutUnits||""==this.bottomInUnits?"hidden":"visible");this.map.events.register("moveend",this,this.update);this.update();return this.div},getBarLen:function(a){var b=parseInt(Math.log(a)/Math.log(10)),b=Math.pow(10,b),a=parseInt(a/b);return(5<a?5:2<a?2:1)*b},update:function(){var a=this.map.getResolution();if(a){var b=this.map.getUnits(),c=OpenLayers.INCHES_PER_UNIT,d=this.maxWidth*
2669 a*c[b],e=1;!0===this.geodesic&&(e=(this.map.getGeodesicPixelSize().w||1.0E-6)*this.maxWidth/(d/c.km),d*=e);var f,g;1E5<d?(f=this.topOutUnits,g=this.bottomOutUnits):(f=this.topInUnits,g=this.bottomInUnits);var h=d/c[f],i=d/c[g],d=this.getBarLen(h),j=this.getBarLen(i),h=d/c[b]*c[f],i=j/c[b]*c[g],b=h/a/e,a=i/a/e;"visible"==this.eBottom.style.visibility&&(this.eBottom.style.width=Math.round(a)+"px",this.eBottom.innerHTML=j+" "+g);"visible"==this.eTop.style.visibility&&(this.eTop.style.width=Math.round(b)+
2670 "px",this.eTop.innerHTML=d+" "+f)}},CLASS_NAME:"OpenLayers.Control.ScaleLine"});OpenLayers.Icon=OpenLayers.Class({url:null,size:null,offset:null,calculateOffset:null,imageDiv:null,px:null,initialize:function(a,b,c,d){this.url=a;this.size=b||{w:20,h:20};this.offset=c||{x:-(this.size.w/2),y:-(this.size.h/2)};this.calculateOffset=d;a=OpenLayers.Util.createUniqueID("OL_Icon_");this.imageDiv=OpenLayers.Util.createAlphaImageDiv(a)},destroy:function(){this.erase();OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);this.imageDiv.innerHTML="";this.imageDiv=null},clone:function(){return new OpenLayers.Icon(this.url,
2671 this.size,this.offset,this.calculateOffset)},setSize:function(a){null!=a&&(this.size=a);this.draw()},setUrl:function(a){null!=a&&(this.url=a);this.draw()},draw:function(a){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,this.size,this.url,"absolute");this.moveTo(a);return this.imageDiv},erase:function(){null!=this.imageDiv&&null!=this.imageDiv.parentNode&&OpenLayers.Element.remove(this.imageDiv)},setOpacity:function(a){OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,null,null,null,
2672 null,null,null,a)},moveTo:function(a){null!=a&&(this.px=a);null!=this.imageDiv&&(null==this.px?this.display(!1):(this.calculateOffset&&(this.offset=this.calculateOffset(this.size)),OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv,null,{x:this.px.x+this.offset.x,y:this.px.y+this.offset.y})))},display:function(a){this.imageDiv.style.display=a?"":"none"},isDrawn:function(){return this.imageDiv&&this.imageDiv.parentNode&&11!=this.imageDiv.parentNode.nodeType},CLASS_NAME:"OpenLayers.Icon"});OpenLayers.Marker=OpenLayers.Class({icon:null,lonlat:null,events:null,map:null,initialize:function(a,b){this.lonlat=a;var c=b?b:OpenLayers.Marker.defaultIcon();null==this.icon?this.icon=c:(this.icon.url=c.url,this.icon.size=c.size,this.icon.offset=c.offset,this.icon.calculateOffset=c.calculateOffset);this.events=new OpenLayers.Events(this,this.icon.imageDiv)},destroy:function(){this.erase();this.map=null;this.events.destroy();this.events=null;null!=this.icon&&(this.icon.destroy(),this.icon=null)},
2673 draw:function(a){return this.icon.draw(a)},erase:function(){null!=this.icon&&this.icon.erase()},moveTo:function(a){null!=a&&null!=this.icon&&this.icon.moveTo(a);this.lonlat=this.map.getLonLatFromLayerPx(a)},isDrawn:function(){return this.icon&&this.icon.isDrawn()},onScreen:function(){var a=!1;this.map&&(a=this.map.getExtent().containsLonLat(this.lonlat));return a},inflate:function(a){this.icon&&this.icon.setSize({w:this.icon.size.w*a,h:this.icon.size.h*a})},setOpacity:function(a){this.icon.setOpacity(a)},
2674 setUrl:function(a){this.icon.setUrl(a)},display:function(a){this.icon.display(a)},CLASS_NAME:"OpenLayers.Marker"});OpenLayers.Marker.defaultIcon=function(){return new OpenLayers.Icon(OpenLayers.Util.getImageLocation("marker.png"),{w:21,h:25},{x:-10.5,y:-25})};OpenLayers.Layer.TileCache=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,format:"image/png",serverResolutions:null,initialize:function(a,b,c,d){this.layername=c;OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,{},d]);this.extension=this.format.split("/")[1].toLowerCase();this.extension="jpg"==this.extension?"jpeg":this.extension},clone:function(a){null==a&&(a=new OpenLayers.Layer.TileCache(this.name,this.url,this.layername,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
2675 [a])},getURL:function(a){function b(a,b){for(var a=""+a,c=[],d=0;d<b;++d)c.push("0");return c.join("").substring(0,b-a.length)+a}var c=this.getServerResolution(),d=this.maxExtent,e=this.tileSize,f=Math.round((a.left-d.left)/(c*e.w)),a=Math.round((a.bottom-d.bottom)/(c*e.h)),c=null!=this.serverResolutions?OpenLayers.Util.indexOf(this.serverResolutions,c):this.map.getZoom(),f=[this.layername,b(c,2),b(parseInt(f/1E6),3),b(parseInt(f/1E3)%1E3,3),b(parseInt(f)%1E3,3),b(parseInt(a/1E6),3),b(parseInt(a/
2676 1E3)%1E3,3),b(parseInt(a)%1E3,3)+"."+this.extension].join("/"),c=this.url;OpenLayers.Util.isArray(c)&&(c=this.selectUrl(f,c));c="/"==c.charAt(c.length-1)?c:c+"/";return c+f},CLASS_NAME:"OpenLayers.Layer.TileCache"});OpenLayers.Layer.KaMap=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,DEFAULT_PARAMS:{i:"jpeg",map:""},initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS)},getURL:function(a){var a=this.adjustBounds(a),b=this.map.getResolution(),c=Math.round(1E4*this.map.getScale())/1E4,d=Math.round(a.left/b);return this.getFullRequestString({t:-Math.round(a.top/b),l:d,s:c})},calculateGridLayout:function(a,
2677 b,c){var b=c*this.tileSize.w,c=c*this.tileSize.h,d=a.left,e=Math.floor(d/b)-this.buffer,d=-(d/b-e)*this.tileSize.w,e=e*b,a=a.top,f=Math.ceil(a/c)+this.buffer;return{tilelon:b,tilelat:c,tileoffsetlon:e,tileoffsetlat:f*c,tileoffsetx:d,tileoffsety:-(f-a/c+1)*this.tileSize.h}},clone:function(a){null==a&&(a=new OpenLayers.Layer.KaMap(this.name,this.url,this.params,this.getOptions()));a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a]);null!=this.tileSize&&(a.tileSize=this.tileSize.clone());a.grid=
2678 [];return a},getTileBounds:function(a){var b=this.getResolution(),c=b*this.tileSize.w,b=b*this.tileSize.h,d=this.getLonLatFromViewPortPx(a),a=c*Math.floor(d.lon/c),d=b*Math.floor(d.lat/b);return new OpenLayers.Bounds(a,d,a+c,d+b)},CLASS_NAME:"OpenLayers.Layer.KaMap"});OpenLayers.Control.TransformFeature=OpenLayers.Class(OpenLayers.Control,{geometryTypes:null,layer:null,preserveAspectRatio:!1,rotate:!0,feature:null,renderIntent:"temporary",rotationHandleSymbolizer:null,box:null,center:null,scale:1,ratio:1,rotation:0,handles:null,rotationHandles:null,dragControl:null,irregular:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.layer=a;this.rotationHandleSymbolizer||(this.rotationHandleSymbolizer={stroke:!1,pointRadius:10,fillOpacity:0,
2679 cursor:"pointer"});this.createBox();this.createControl()},activate:function(){var a=!1;OpenLayers.Control.prototype.activate.apply(this,arguments)&&(this.dragControl.activate(),this.layer.addFeatures([this.box]),this.rotate&&this.layer.addFeatures(this.rotationHandles),this.layer.addFeatures(this.handles),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Control.prototype.deactivate.apply(this,arguments)&&(this.layer.removeFeatures(this.handles),this.rotate&&this.layer.removeFeatures(this.rotationHandles),
2680 this.layer.removeFeatures([this.box]),this.dragControl.deactivate(),a=!0);return a},setMap:function(a){this.dragControl.setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},setFeature:function(a,b){var b=OpenLayers.Util.applyDefaults(b,{rotation:0,scale:1,ratio:1}),c=this.rotation,d=this.center;OpenLayers.Util.extend(this,b);if(!1!==this.events.triggerEvent("beforesetfeature",{feature:a})){this.feature=a;this.activate();this._setfeature=!0;var e=this.feature.geometry.getBounds();this.box.move(e.getCenterLonLat());
2681 this.box.geometry.rotate(-c,d);this._angle=0;this.rotation?(c=a.geometry.clone(),c.rotate(-this.rotation,this.center),c=new OpenLayers.Feature.Vector(c.getBounds().toGeometry()),c.geometry.rotate(this.rotation,this.center),this.box.geometry.rotate(this.rotation,this.center),this.box.move(c.geometry.getBounds().getCenterLonLat()),c=c.geometry.components[0].components[0].getBounds().getCenterLonLat()):c=new OpenLayers.LonLat(e.left,e.bottom);this.handles[0].move(c);delete this._setfeature;this.events.triggerEvent("setfeature",
2682 {feature:a})}},unsetFeature:function(){this.active?this.deactivate():(this.feature=null,this.rotation=0,this.ratio=this.scale=1)},createBox:function(){var a=this;this.center=new OpenLayers.Geometry.Point(0,0);this.box=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString([new OpenLayers.Geometry.Point(-1,-1),new OpenLayers.Geometry.Point(0,-1),new OpenLayers.Geometry.Point(1,-1),new OpenLayers.Geometry.Point(1,0),new OpenLayers.Geometry.Point(1,1),new OpenLayers.Geometry.Point(0,1),new OpenLayers.Geometry.Point(-1,
2683 1),new OpenLayers.Geometry.Point(-1,0),new OpenLayers.Geometry.Point(-1,-1)]),null,"string"==typeof this.renderIntent?null:this.renderIntent);this.box.geometry.move=function(b,c){a._moving=!0;OpenLayers.Geometry.LineString.prototype.move.apply(this,arguments);a.center.move(b,c);delete a._moving};for(var b=function(a,b){OpenLayers.Geometry.Point.prototype.move.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.move(a,b);this._handle.geometry.move(a,b)},c=function(a,b,c){OpenLayers.Geometry.Point.prototype.resize.apply(this,
2684 arguments);this._rotationHandle&&this._rotationHandle.geometry.resize(a,b,c);this._handle.geometry.resize(a,b,c)},d=function(a,b){OpenLayers.Geometry.Point.prototype.rotate.apply(this,arguments);this._rotationHandle&&this._rotationHandle.geometry.rotate(a,b);this._handle.geometry.rotate(a,b)},e=function(b,c){var d=this.x,e=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,b,c);if(!a._moving){var f=a.dragControl.handlers.drag.evt,g=!(!a._setfeature&&a.preserveAspectRatio)&&!(f&&f.shiftKey),
2685 h=new OpenLayers.Geometry.Point(d,e),f=a.center;this.rotate(-a.rotation,f);h.rotate(-a.rotation,f);var i=this.x-f.x,j=this.y-f.y,k=i-(this.x-h.x),l=j-(this.y-h.y);a.irregular&&!a._setfeature&&(i-=(this.x-h.x)/2,j-=(this.y-h.y)/2);this.x=d;this.y=e;h=1;g?(j=1.0E-5>Math.abs(l)?1:j/l,h=(1.0E-5>Math.abs(k)?1:i/k)/j):(k=Math.sqrt(k*k+l*l),j=Math.sqrt(i*i+j*j)/k);a._moving=!0;a.box.geometry.rotate(-a.rotation,f);delete a._moving;a.box.geometry.resize(j,f,h);a.box.geometry.rotate(a.rotation,f);a.transformFeature({scale:j,
2686 ratio:h});a.irregular&&!a._setfeature&&(i=f.clone(),i.x+=1.0E-5>Math.abs(d-f.x)?0:this.x-d,i.y+=1.0E-5>Math.abs(e-f.y)?0:this.y-e,a.box.geometry.move(this.x-d,this.y-e),a.transformFeature({center:i}))}},f=function(b,c){var d=this.x,e=this.y;OpenLayers.Geometry.Point.prototype.move.call(this,b,c);if(!a._moving){var f=a.dragControl.handlers.drag.evt,f=f&&f.shiftKey?45:1,g=a.center,h=this.x-g.x,i=this.y-g.y;this.x=d;this.y=e;d=Math.atan2(i-c,h-b);d=Math.atan2(i,h)-d;d*=180/Math.PI;a._angle=(a._angle+
2687 d)%360;d=a.rotation%f;if(Math.abs(a._angle)>=f||0!==d)d=Math.round(a._angle/f)*f-d,a._angle=0,a.box.geometry.rotate(d,g),a.transformFeature({rotation:d})}},g=Array(8),h=Array(4),i,j,k,l="sw s se e ne n nw w".split(" "),m=0;8>m;++m)i=this.box.geometry.components[m],j=new OpenLayers.Feature.Vector(i.clone(),{role:l[m]+"-resize"},"string"==typeof this.renderIntent?null:this.renderIntent),0==m%2&&(k=new OpenLayers.Feature.Vector(i.clone(),{role:l[m]+"-rotate"},"string"==typeof this.rotationHandleSymbolizer?
2688 null:this.rotationHandleSymbolizer),k.geometry.move=f,i._rotationHandle=k,h[m/2]=k),i.move=b,i.resize=c,i.rotate=d,j.geometry.move=e,i._handle=j,g[m]=j;this.rotationHandles=h;this.handles=g},createControl:function(){var a=this;this.dragControl=new OpenLayers.Control.DragFeature(this.layer,{documentDrag:!0,moveFeature:function(b){this.feature===a.feature&&(this.feature=a.box);OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,arguments)},onDrag:function(b){b===a.box&&a.transformFeature({center:a.center})},
2689 onStart:function(b){var c=!a.geometryTypes||-1!==OpenLayers.Util.indexOf(a.geometryTypes,b.geometry.CLASS_NAME),d=OpenLayers.Util.indexOf(a.handles,b),d=d+OpenLayers.Util.indexOf(a.rotationHandles,b);b!==a.feature&&(b!==a.box&&-2==d&&c)&&a.setFeature(b)},onComplete:function(){a.events.triggerEvent("transformcomplete",{feature:a.feature})}})},drawHandles:function(){for(var a=this.layer,b=0;8>b;++b)this.rotate&&0===b%2&&a.drawFeature(this.rotationHandles[b/2],this.rotationHandleSymbolizer),a.drawFeature(this.handles[b],
2690 this.renderIntent)},transformFeature:function(a){if(!this._setfeature){this.scale*=a.scale||1;this.ratio*=a.ratio||1;var b=this.rotation;this.rotation=(this.rotation+(a.rotation||0))%360;if(!1!==this.events.triggerEvent("beforetransform",a)){var c=this.feature,d=c.geometry,e=this.center;d.rotate(-b,e);a.scale||a.ratio?d.resize(a.scale,e,a.ratio):a.center&&c.move(a.center.getBounds().getCenterLonLat());d.rotate(this.rotation,e);this.layer.drawFeature(c);c.toState(OpenLayers.State.UPDATE);this.events.triggerEvent("transform",
2691 a)}}this.layer.drawFeature(this.box,this.renderIntent);this.drawHandles()},destroy:function(){for(var a,b=0;8>b;++b)a=this.box.geometry.components[b],a._handle.destroy(),a._handle=null,a._rotationHandle&&a._rotationHandle.destroy(),a._rotationHandle=null;this.rotationHandles=this.rotationHandleSymbolizer=this.handles=this.feature=this.center=null;this.box.destroy();this.layer=this.box=null;this.dragControl.destroy();this.dragControl=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},
2692 CLASS_NAME:"OpenLayers.Control.TransformFeature"});OpenLayers.Handler.Box=OpenLayers.Class(OpenLayers.Handler,{dragHandler:null,boxDivClassName:"olHandlerBoxZoomBox",boxOffsets:null,initialize:function(a,b,c){OpenLayers.Handler.prototype.initialize.apply(this,arguments);this.dragHandler=new OpenLayers.Handler.Drag(this,{down:this.startBox,move:this.moveBox,out:this.removeBox,up:this.endBox},{keyMask:this.keyMask})},destroy:function(){OpenLayers.Handler.prototype.destroy.apply(this,arguments);this.dragHandler&&(this.dragHandler.destroy(),this.dragHandler=
2693 null)},setMap:function(a){OpenLayers.Handler.prototype.setMap.apply(this,arguments);this.dragHandler&&this.dragHandler.setMap(a)},startBox:function(){this.callback("start",[]);this.zoomBox=OpenLayers.Util.createDiv("zoomBox",{x:-9999,y:-9999});this.zoomBox.className=this.boxDivClassName;this.zoomBox.style.zIndex=this.map.Z_INDEX_BASE.Popup-1;this.map.viewPortDiv.appendChild(this.zoomBox);OpenLayers.Element.addClass(this.map.viewPortDiv,"olDrawBox")},moveBox:function(a){var b=this.dragHandler.start.x,
2694 c=this.dragHandler.start.y,d=Math.abs(b-a.x),e=Math.abs(c-a.y),f=this.getBoxOffsets();this.zoomBox.style.width=d+f.width+1+"px";this.zoomBox.style.height=e+f.height+1+"px";this.zoomBox.style.left=(a.x<b?b-d-f.left:b-f.left)+"px";this.zoomBox.style.top=(a.y<c?c-e-f.top:c-f.top)+"px"},endBox:function(a){var b;if(5<Math.abs(this.dragHandler.start.x-a.x)||5<Math.abs(this.dragHandler.start.y-a.y)){var c=this.dragHandler.start;b=Math.min(c.y,a.y);var d=Math.max(c.y,a.y),e=Math.min(c.x,a.x),a=Math.max(c.x,
2695 a.x);b=new OpenLayers.Bounds(e,d,a,b)}else b=this.dragHandler.start.clone();this.removeBox();this.callback("done",[b])},removeBox:function(){this.map.viewPortDiv.removeChild(this.zoomBox);this.boxOffsets=this.zoomBox=null;OpenLayers.Element.removeClass(this.map.viewPortDiv,"olDrawBox")},activate:function(){return OpenLayers.Handler.prototype.activate.apply(this,arguments)?(this.dragHandler.activate(),!0):!1},deactivate:function(){return OpenLayers.Handler.prototype.deactivate.apply(this,arguments)?
2696 (this.dragHandler.deactivate()&&this.zoomBox&&this.removeBox(),!0):!1},getBoxOffsets:function(){if(!this.boxOffsets){var a=document.createElement("div");a.style.position="absolute";a.style.border="1px solid black";a.style.width="3px";document.body.appendChild(a);var b=3==a.clientWidth;document.body.removeChild(a);var a=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-left-width")),c=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-right-width")),d=parseInt(OpenLayers.Element.getStyle(this.zoomBox,
2697 "border-top-width")),e=parseInt(OpenLayers.Element.getStyle(this.zoomBox,"border-bottom-width"));this.boxOffsets={left:a,right:c,top:d,bottom:e,width:!1===b?a+c:0,height:!1===b?d+e:0}}return this.boxOffsets},CLASS_NAME:"OpenLayers.Handler.Box"});OpenLayers.Control.ZoomBox=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,out:!1,keyMask:null,alwaysZoom:!1,draw:function(){this.handler=new OpenLayers.Handler.Box(this,{done:this.zoomBox},{keyMask:this.keyMask})},zoomBox:function(a){if(a instanceof OpenLayers.Bounds){var b;if(this.out){b=Math.abs(a.right-a.left);var c=Math.abs(a.top-a.bottom);b=Math.min(this.map.size.h/c,this.map.size.w/b);var c=this.map.getExtent(),d=this.map.getLonLatFromPixel(a.getCenterPixel()),a=d.lon-
2698 c.getWidth()/2*b,e=d.lon+c.getWidth()/2*b,f=d.lat-c.getHeight()/2*b;b=d.lat+c.getHeight()/2*b;b=new OpenLayers.Bounds(a,f,e,b)}else b=this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),c=this.map.getLonLatFromPixel({x:a.right,y:a.top}),b=new OpenLayers.Bounds(b.lon,b.lat,c.lon,c.lat);c=this.map.getZoom();this.map.zoomToExtent(b);c==this.map.getZoom()&&!0==this.alwaysZoom&&this.map.zoomTo(c+(this.out?-1:1))}else this.out?this.map.setCenter(this.map.getLonLatFromPixel(a),this.map.getZoom()-1):this.map.setCenter(this.map.getLonLatFromPixel(a),
2699 this.map.getZoom()+1)},CLASS_NAME:"OpenLayers.Control.ZoomBox"});OpenLayers.Control.DragPan=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,panned:!1,interval:1,documentDrag:!1,kinetic:null,enableKinetic:!1,kineticInterval:10,draw:function(){if(this.enableKinetic){var a={interval:this.kineticInterval};"object"===typeof this.enableKinetic&&(a=OpenLayers.Util.extend(a,this.enableKinetic));this.kinetic=new OpenLayers.Kinetic(a)}this.handler=new OpenLayers.Handler.Drag(this,{move:this.panMap,done:this.panMapDone,down:this.panMapStart},{interval:this.interval,
2700 documentDrag:this.documentDrag})},panMapStart:function(){this.kinetic&&this.kinetic.begin()},panMap:function(a){this.kinetic&&this.kinetic.update(a);this.panned=!0;this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!0,animate:!1})},panMapDone:function(a){if(this.panned){var b=null;this.kinetic&&(b=this.kinetic.end(a));this.map.pan(this.handler.last.x-a.x,this.handler.last.y-a.y,{dragging:!!b,animate:!1});if(b){var c=this;this.kinetic.move(b,function(a,b,f){c.map.pan(a,b,{dragging:!f,
2701 animate:!1})})}this.panned=!1}},CLASS_NAME:"OpenLayers.Control.DragPan"});OpenLayers.Handler.Click=OpenLayers.Class(OpenLayers.Handler,{delay:300,single:!0,"double":!1,pixelTolerance:0,dblclickTolerance:13,stopSingle:!1,stopDouble:!1,timerId:null,touch:!1,down:null,last:null,first:null,rightclickTimerId:null,touchstart:function(a){this.touch||(this.unregisterMouseListeners(),this.touch=!0);this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return!0},touchmove:function(a){this.last=this.getEventInfo(a);return!0},touchend:function(a){this.down&&(a.xy=this.last.xy,
2702 a.lastTouches=this.last.touches,this.handleSingle(a),this.down=null);return!0},unregisterMouseListeners:function(){this.map.events.un({mousedown:this.mousedown,mouseup:this.mouseup,click:this.click,dblclick:this.dblclick,scope:this})},mousedown:function(a){this.down=this.getEventInfo(a);this.last=this.getEventInfo(a);return!0},mouseup:function(a){var b=!0;this.checkModifiers(a)&&(this.control.handleRightClicks&&OpenLayers.Event.isRightClick(a))&&(b=this.rightclick(a));return b},rightclick:function(a){if(this.passesTolerance(a)){if(null!=
2703 this.rightclickTimerId)return this.clearTimer(),this.callback("dblrightclick",[a]),!this.stopDouble;a=this["double"]?OpenLayers.Util.extend({},a):this.callback("rightclick",[a]);a=OpenLayers.Function.bind(this.delayedRightCall,this,a);this.rightclickTimerId=window.setTimeout(a,this.delay)}return!this.stopSingle},delayedRightCall:function(a){this.rightclickTimerId=null;a&&this.callback("rightclick",[a])},click:function(a){this.last||(this.last=this.getEventInfo(a));this.handleSingle(a);return!this.stopSingle},
2704 dblclick:function(a){this.handleDouble(a);return!this.stopDouble},handleDouble:function(a){this.passesDblclickTolerance(a)&&(this["double"]&&this.callback("dblclick",[a]),this.clearTimer())},handleSingle:function(a){this.passesTolerance(a)&&(null!=this.timerId?(this.last.touches&&1===this.last.touches.length&&(this["double"]&&OpenLayers.Event.stop(a),this.handleDouble(a)),(!this.last.touches||2!==this.last.touches.length)&&this.clearTimer()):(this.first=this.getEventInfo(a),this.queuePotentialClick(this.single?
2705 OpenLayers.Util.extend({},a):null)))},queuePotentialClick:function(a){this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,a),this.delay)},passesTolerance:function(a){var b=!0;if(null!=this.pixelTolerance&&this.down&&this.down.xy&&(b=this.pixelTolerance>=this.down.xy.distanceTo(a.xy))&&this.touch&&this.down.touches.length===this.last.touches.length)for(var a=0,c=this.down.touches.length;a<c;++a)if(this.getTouchDistance(this.down.touches[a],this.last.touches[a])>this.pixelTolerance){b=
2706 !1;break}return b},getTouchDistance:function(a,b){return Math.sqrt(Math.pow(a.clientX-b.clientX,2)+Math.pow(a.clientY-b.clientY,2))},passesDblclickTolerance:function(){var a=!0;this.down&&this.first&&(a=this.down.xy.distanceTo(this.first.xy)<=this.dblclickTolerance);return a},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null);null!=this.rightclickTimerId&&(window.clearTimeout(this.rightclickTimerId),this.rightclickTimerId=null)},delayedCall:function(a){this.timerId=
2707 null;a&&this.callback("click",[a])},getEventInfo:function(a){var b;if(a.touches){var c=a.touches.length;b=Array(c);for(var d,e=0;e<c;e++)d=a.touches[e],b[e]={clientX:d.clientX,clientY:d.clientY}}return{xy:a.xy,touches:b}},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.clearTimer(),this.last=this.first=this.down=null,this.touch=!1,a=!0);return a},CLASS_NAME:"OpenLayers.Handler.Click"});OpenLayers.Control.Navigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,documentDrag:!1,zoomBox:null,zoomBoxEnabled:!0,zoomWheelEnabled:!0,mouseWheelOptions:null,handleRightClicks:!1,zoomBoxKeyMask:OpenLayers.Handler.MOD_SHIFT,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null;
2708 this.zoomBox&&this.zoomBox.destroy();this.zoomBox=null;this.pinchZoom&&this.pinchZoom.destroy();this.pinchZoom=null;OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){this.dragPan.activate();this.zoomWheelEnabled&&this.handlers.wheel.activate();this.handlers.click.activate();this.zoomBoxEnabled&&this.zoomBox.activate();this.pinchZoom&&this.pinchZoom.activate();return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){this.pinchZoom&&this.pinchZoom.deactivate();
2709 this.zoomBox.deactivate();this.dragPan.deactivate();this.handlers.click.deactivate();this.handlers.wheel.deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},draw:function(){this.handleRightClicks&&(this.map.viewPortDiv.oncontextmenu=OpenLayers.Function.False);this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.defaultClick,dblclick:this.defaultDblClick,dblrightclick:this.defaultDblRightClick},{"double":!0,stopDouble:!0});this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,
2710 documentDrag:this.documentDrag},this.dragPanOptions));this.zoomBox=new OpenLayers.Control.ZoomBox({map:this.map,keyMask:this.zoomBoxKeyMask});this.dragPan.draw();this.zoomBox.draw();this.handlers.wheel=new OpenLayers.Handler.MouseWheel(this,{up:this.wheelUp,down:this.wheelDown},this.mouseWheelOptions);OpenLayers.Control.PinchZoom&&(this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions)))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&&
2711 this.map.zoomOut()},defaultDblClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom+1)},defaultDblRightClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),this.map.zoom-1)},wheelChange:function(a,b){var c=this.map.getZoom(),d=this.map.getZoom()+Math.round(b),d=Math.max(d,0),d=Math.min(d,this.map.getNumZoomLevels());if(d!==c){var e=this.map.getSize(),c=e.w/2-a.xy.x,e=a.xy.y-e.h/2,f=this.map.baseLayer.getResolutionForZoom(d),g=this.map.getLonLatFromPixel(a.xy);
2712 this.map.setCenter(new OpenLayers.LonLat(g.lon+c*f,g.lat+e*f),d)}},wheelUp:function(a,b){this.wheelChange(a,b||1)},wheelDown:function(a,b){this.wheelChange(a,b||-1)},disableZoomBox:function(){this.zoomBoxEnabled=!1;this.zoomBox.deactivate()},enableZoomBox:function(){this.zoomBoxEnabled=!0;this.active&&this.zoomBox.activate()},disableZoomWheel:function(){this.zoomWheelEnabled=!1;this.handlers.wheel.deactivate()},enableZoomWheel:function(){this.zoomWheelEnabled=!0;this.active&&this.handlers.wheel.activate()},
2713 CLASS_NAME:"OpenLayers.Control.Navigation"});OpenLayers.Control.DrawFeature=OpenLayers.Class(OpenLayers.Control,{layer:null,callbacks:null,multi:!1,featureAdded:function(){},handlerOptions:null,initialize:function(a,b,c){OpenLayers.Control.prototype.initialize.apply(this,[c]);this.callbacks=OpenLayers.Util.extend({done:this.drawFeature,modify:function(a,b){this.layer.events.triggerEvent("sketchmodified",{vertex:a,feature:b})},create:function(a,b){this.layer.events.triggerEvent("sketchstarted",{vertex:a,feature:b})}},this.callbacks);this.layer=
2714 a;this.handlerOptions=this.handlerOptions||{};this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{renderers:a.renderers,rendererOptions:a.rendererOptions});"multi"in this.handlerOptions||(this.handlerOptions.multi=this.multi);if(a=this.layer.styleMap&&this.layer.styleMap.styles.temporary)this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":a})});this.handler=new b(this,
2715 this.callbacks,this.handlerOptions)},drawFeature:function(a){a=new OpenLayers.Feature.Vector(a);!1!==this.layer.events.triggerEvent("sketchcomplete",{feature:a})&&(a.state=OpenLayers.State.INSERT,this.layer.addFeatures([a]),this.featureAdded(a),this.events.triggerEvent("featureadded",{feature:a}))},insertXY:function(a,b){this.handler&&this.handler.line&&this.handler.insertXY(a,b)},insertDeltaXY:function(a,b){this.handler&&this.handler.line&&this.handler.insertDeltaXY(a,b)},insertDirectionLength:function(a,
2716 b){this.handler&&this.handler.line&&this.handler.insertDirectionLength(a,b)},insertDeflectionLength:function(a,b){this.handler&&this.handler.line&&this.handler.insertDeflectionLength(a,b)},undo:function(){return this.handler.undo&&this.handler.undo()},redo:function(){return this.handler.redo&&this.handler.redo()},finishSketch:function(){this.handler.finishGeometry()},cancel:function(){this.handler.cancel()},CLASS_NAME:"OpenLayers.Control.DrawFeature"});OpenLayers.Handler.Polygon=OpenLayers.Class(OpenLayers.Handler.Path,{holeModifier:null,drawingHole:!1,polygon:null,createFeature:function(a){a=this.layer.getLonLatFromViewPortPx(a);a=new OpenLayers.Geometry.Point(a.lon,a.lat);this.point=new OpenLayers.Feature.Vector(a);this.line=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LinearRing([this.point.geometry]));this.polygon=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon([this.line.geometry]));this.callback("create",[this.point.geometry,
2717 this.getSketch()]);this.point.geometry.clearBounds();this.layer.addFeatures([this.polygon,this.point],{silent:!0})},addPoint:function(a){if(!this.drawingHole&&this.holeModifier&&this.evt&&this.evt[this.holeModifier])for(var b=this.point.geometry,c=this.control.layer.features,d,e=c.length-1;0<=e;--e)if(d=c[e].geometry,(d instanceof OpenLayers.Geometry.Polygon||d instanceof OpenLayers.Geometry.MultiPolygon)&&d.intersects(b)){b=c[e];this.control.layer.removeFeatures([b],{silent:!0});this.control.layer.events.registerPriority("sketchcomplete",
2718 this,this.finalizeInteriorRing);this.control.layer.events.registerPriority("sketchmodified",this,this.enforceTopology);b.geometry.addComponent(this.line.geometry);this.polygon=b;this.drawingHole=!0;break}OpenLayers.Handler.Path.prototype.addPoint.apply(this,arguments)},getCurrentPointIndex:function(){return this.line.geometry.components.length-2},enforceTopology:function(a){var a=a.vertex,b=this.line.geometry.components;this.polygon.geometry.intersects(a)||(b=b[b.length-3],a.x=b.x,a.y=b.y)},finishGeometry:function(){this.line.geometry.removeComponent(this.line.geometry.components[this.line.geometry.components.length-
2719 2]);this.removePoint();this.finalize()},finalizeInteriorRing:function(){var a=this.line.geometry,b=0!==a.getArea();if(b){for(var c=this.polygon.geometry.components,d=c.length-2;0<=d;--d)if(a.intersects(c[d])){b=!1;break}if(b){d=c.length-2;a:for(;0<d;--d)for(var e=c[d].components,f=0,g=e.length;f<g;++f)if(a.containsPoint(e[f])){b=!1;break a}}}b?this.polygon.state!==OpenLayers.State.INSERT&&(this.polygon.state=OpenLayers.State.UPDATE):this.polygon.geometry.removeComponent(a);this.restoreFeature();return!1},
2720 cancel:function(){this.drawingHole&&(this.polygon.geometry.removeComponent(this.line.geometry),this.restoreFeature(!0));return OpenLayers.Handler.Path.prototype.cancel.apply(this,arguments)},restoreFeature:function(a){this.control.layer.events.unregister("sketchcomplete",this,this.finalizeInteriorRing);this.control.layer.events.unregister("sketchmodified",this,this.enforceTopology);this.layer.removeFeatures([this.polygon],{silent:!0});this.control.layer.addFeatures([this.polygon],{silent:!0});this.drawingHole=
2721 !1;a||this.control.layer.events.triggerEvent("sketchcomplete",{feature:this.polygon})},destroyFeature:function(a){OpenLayers.Handler.Path.prototype.destroyFeature.call(this,a);this.polygon=null},drawFeature:function(){this.layer.drawFeature(this.polygon,this.style);this.layer.drawFeature(this.point,this.style)},getSketch:function(){return this.polygon},getGeometry:function(){var a=this.polygon&&this.polygon.geometry;a&&this.multi&&(a=new OpenLayers.Geometry.MultiPolygon([a]));return a},CLASS_NAME:"OpenLayers.Handler.Polygon"});OpenLayers.Control.EditingToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{citeCompliant:!1,initialize:function(a,b){OpenLayers.Control.Panel.prototype.initialize.apply(this,[b]);this.addControls([new OpenLayers.Control.Navigation]);this.addControls([new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Point,{displayClass:"olControlDrawFeaturePoint",handlerOptions:{citeCompliant:this.citeCompliant}}),new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Path,{displayClass:"olControlDrawFeaturePath",
2722 handlerOptions:{citeCompliant:this.citeCompliant}}),new OpenLayers.Control.DrawFeature(a,OpenLayers.Handler.Polygon,{displayClass:"olControlDrawFeaturePolygon",handlerOptions:{citeCompliant:this.citeCompliant}})])},draw:function(){var a=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);null===this.defaultControl&&(this.defaultControl=this.controls[0]);return a},CLASS_NAME:"OpenLayers.Control.EditingToolbar"});OpenLayers.Strategy.BBOX=OpenLayers.Class(OpenLayers.Strategy,{bounds:null,resolution:null,ratio:2,resFactor:null,response:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);a&&(this.layer.events.on({moveend:this.update,refresh:this.update,visibilitychanged:this.update,scope:this}),this.update());return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.layer.events.un({moveend:this.update,refresh:this.update,visibilitychanged:this.update,
2723 scope:this});return a},update:function(a){var b=this.getMapBounds();if(null!==b&&(a&&a.force||this.layer.visibility&&this.layer.calculateInRange()&&this.invalidBounds(b)))this.calculateBounds(b),this.resolution=this.layer.map.getResolution(),this.triggerRead(a)},getMapBounds:function(){if(null===this.layer.map)return null;var a=this.layer.map.getExtent();a&&!this.layer.projection.equals(this.layer.map.getProjectionObject())&&(a=a.clone().transform(this.layer.map.getProjectionObject(),this.layer.projection));
2724 return a},invalidBounds:function(a){a||(a=this.getMapBounds());a=!this.bounds||!this.bounds.containsBounds(a);!a&&this.resFactor&&(a=this.resolution/this.layer.map.getResolution(),a=a>=this.resFactor||a<=1/this.resFactor);return a},calculateBounds:function(a){a||(a=this.getMapBounds());var b=a.getCenterLonLat(),c=a.getWidth()*this.ratio,a=a.getHeight()*this.ratio;this.bounds=new OpenLayers.Bounds(b.lon-c/2,b.lat-a/2,b.lon+c/2,b.lat+a/2)},triggerRead:function(a){this.response&&!(a&&!0===a.noAbort)&&
2725 (this.layer.protocol.abort(this.response),this.layer.events.triggerEvent("loadend"));this.layer.events.triggerEvent("loadstart");this.response=this.layer.protocol.read(OpenLayers.Util.applyDefaults({filter:this.createFilter(),callback:this.merge,scope:this},a))},createFilter:function(){var a=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,value:this.bounds,projection:this.layer.projection});this.layer.filter&&(a=new OpenLayers.Filter.Logical({type:OpenLayers.Filter.Logical.AND,
2726 filters:[this.layer.filter,a]}));return a},merge:function(a){this.layer.destroyFeatures();if((a=a.features)&&0<a.length){var b=this.layer.projection,c=this.layer.map.getProjectionObject();if(!c.equals(b))for(var d,e=0,f=a.length;e<f;++e)(d=a[e].geometry)&&d.transform(b,c);this.layer.addFeatures(a)}this.response=null;this.layer.events.triggerEvent("loadend")},CLASS_NAME:"OpenLayers.Strategy.BBOX"});OpenLayers.Layer.WorldWind=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{},isBaseLayer:!0,lzd:null,zoomLevels:null,initialize:function(a,b,c,d,e,f){this.lzd=c;this.zoomLevels=d;c=[];c.push(a,b,e,f);OpenLayers.Layer.Grid.prototype.initialize.apply(this,c);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS)},getZoom:function(){var a=this.map.getZoom();this.map.getMaxExtent();return a-=Math.log(this.maxResolution/(this.lzd/512))/Math.log(2)},getURL:function(a){var a=
2727 this.adjustBounds(a),b=this.getZoom(),c=this.map.getMaxExtent(),d=this.lzd/Math.pow(2,this.getZoom()),e=Math.floor((a.left-c.left)/d),a=Math.floor((a.bottom-c.bottom)/d);return this.map.getResolution()<=this.lzd/512&&this.getZoom()<=this.zoomLevels?this.getFullRequestString({L:b,X:e,Y:a}):OpenLayers.Util.getImageLocation("blank.gif")},CLASS_NAME:"OpenLayers.Layer.WorldWind"});OpenLayers.Protocol.CSW=function(a){var a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.CSW.DEFAULTS),b=OpenLayers.Protocol.CSW["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported CSW version: "+a.version;return new b(a)};OpenLayers.Protocol.CSW.DEFAULTS={version:"2.0.2"};OpenLayers.Format.WMTSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",yx:{"urn:ogc:def:crs:EPSG::4326":!0},createLayer:function(a,b){var c,d={layer:!0,matrixSet:!0},e;for(e in d)if(!(e in b))throw Error("Missing property '"+e+"' in layer configuration.");d=a.contents;e=d.tileMatrixSets[b.matrixSet];for(var f,g=0,h=d.layers.length;g<h;++g)if(d.layers[g].identifier===b.layer){f=d.layers[g];break}if(f&&e){for(var i,g=0,h=f.styles.length;g<h&&!(i=f.styles[g],i.isDefault);++g);
2728 c=new OpenLayers.Layer.WMTS(OpenLayers.Util.applyDefaults(b,{url:"REST"===b.requestEncoding&&f.resourceUrl?f.resourceUrl.tile.template:a.operationsMetadata.GetTile.dcp.http.get[0].url,name:f.title,style:i.identifier,matrixIds:e.matrixIds,tileFullExtent:e.bounds}))}return c},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities"});OpenLayers.Layer.Google.v3={DEFAULTS:{sphericalMercator:!0,projection:"EPSG:900913"},animationEnabled:!0,loadMapObject:function(){this.type||(this.type=google.maps.MapTypeId.ROADMAP);var a,b=OpenLayers.Layer.Google.cache[this.map.id];b?(a=b.mapObject,++b.count):(b=this.map.viewPortDiv,a=document.createElement("div"),a.id=this.map.id+"_GMapContainer",a.style.position="absolute",a.style.width="100%",a.style.height="100%",b.appendChild(a),b=this.map.getCenter(),a=new google.maps.Map(a,{center:b?new google.maps.LatLng(b.lat,
2729 b.lon):new google.maps.LatLng(0,0),zoom:this.map.getZoom()||0,mapTypeId:this.type,disableDefaultUI:!0,keyboardShortcuts:!1,draggable:!1,disableDoubleClickZoom:!0,scrollwheel:!1,streetViewControl:!1}),b={mapObject:a,count:1},OpenLayers.Layer.Google.cache[this.map.id]=b,this.repositionListener=google.maps.event.addListenerOnce(a,"center_changed",OpenLayers.Function.bind(this.repositionMapElements,this)));this.mapObject=a;this.setGMapVisibility(this.visibility)},repositionMapElements:function(){google.maps.event.trigger(this.mapObject,
2730 "resize");var a=this.mapObject.getDiv().firstChild;if(!a||3>a.childNodes.length)return this.repositionTimer=window.setTimeout(OpenLayers.Function.bind(this.repositionMapElements,this),250),!1;for(var b=OpenLayers.Layer.Google.cache[this.map.id],c=this.map.viewPortDiv,d=a.children.length-1;0<=d;--d){if(1000001==a.children[d].style.zIndex){var e=a.children[d];c.appendChild(e);e.style.zIndex="1100";e.style.bottom="";e.className="olLayerGoogleCopyright olLayerGoogleV3";e.style.display="";b.termsOfUse=
2731 e}1E6==a.children[d].style.zIndex&&(e=a.children[d],c.appendChild(e),e.style.zIndex="1100",e.style.bottom="",e.className="olLayerGooglePoweredBy olLayerGoogleV3 gmnoprint",e.style.display="",b.poweredBy=e);10000002==a.children[d].style.zIndex&&c.appendChild(a.children[d])}this.setGMapVisibility(this.visibility)},onMapResize:function(){if(this.visibility)google.maps.event.trigger(this.mapObject,"resize");else{var a=OpenLayers.Layer.Google.cache[this.map.id];if(!a.resized){var b=this;google.maps.event.addListenerOnce(this.mapObject,
2732 "tilesloaded",function(){google.maps.event.trigger(b.mapObject,"resize");b.moveTo(b.map.getCenter(),b.map.getZoom());delete a.resized})}a.resized=!0}},setGMapVisibility:function(a){var b=OpenLayers.Layer.Google.cache[this.map.id];if(b){for(var c=this.type,d=this.map.layers,e,f=d.length-1;0<=f;--f)if(e=d[f],e instanceof OpenLayers.Layer.Google&&!0===e.visibility&&!0===e.inRange){c=e.type;a=!0;break}d=this.mapObject.getDiv();!0===a?(this.mapObject.setMapTypeId(c),d.style.left="",b.termsOfUse&&b.termsOfUse.style&&
2733 (b.termsOfUse.style.left="",b.termsOfUse.style.display="",b.poweredBy.style.display=""),b.displayed=this.id):(delete b.displayed,d.style.left="-9999px",b.termsOfUse&&b.termsOfUse.style&&(b.termsOfUse.style.display="none",b.termsOfUse.style.left="-9999px",b.poweredBy.style.display="none"))}},getMapContainer:function(){return this.mapObject.getDiv()},getMapObjectBoundsFromOLBounds:function(a){var b=null;null!=a&&(b=this.sphericalMercator?this.inverseMercator(a.bottom,a.left):new OpenLayers.LonLat(a.bottom,
2734 a.left),a=this.sphericalMercator?this.inverseMercator(a.top,a.right):new OpenLayers.LonLat(a.top,a.right),b=new google.maps.LatLngBounds(new google.maps.LatLng(b.lat,b.lon),new google.maps.LatLng(a.lat,a.lon)));return b},getMapObjectLonLatFromMapObjectPixel:function(a){var b=this.map.getSize(),c=this.getLongitudeFromMapObjectLonLat(this.mapObject.center),d=this.getLatitudeFromMapObjectLonLat(this.mapObject.center),e=this.map.getResolution(),a=new OpenLayers.LonLat(c+(a.x-b.w/2)*e,d-(a.y-b.h/2)*e);
2735 this.wrapDateLine&&(a=a.wrapDateLine(this.maxExtent));return this.getMapObjectLonLatFromLonLat(a.lon,a.lat)},getMapObjectPixelFromMapObjectLonLat:function(a){var b=this.getLongitudeFromMapObjectLonLat(a),a=this.getLatitudeFromMapObjectLonLat(a),c=this.map.getResolution(),d=this.map.getExtent();return this.getMapObjectPixelFromXY(1/c*(b-d.left),1/c*(d.top-a))},setMapObjectCenter:function(a,b){if(!1===this.animationEnabled&&b!=this.mapObject.zoom){var c=this.getMapContainer();google.maps.event.addListenerOnce(this.mapObject,
2736 "idle",function(){c.style.visibility=""});c.style.visibility="hidden"}this.mapObject.setOptions({center:a,zoom:b})},getMapObjectZoomFromMapObjectBounds:function(a){return this.mapObject.getBoundsZoomLevel(a)},getMapObjectLonLatFromLonLat:function(a,b){var c;this.sphericalMercator?(c=this.inverseMercator(a,b),c=new google.maps.LatLng(c.lat,c.lon)):c=new google.maps.LatLng(b,a);return c},getMapObjectPixelFromXY:function(a,b){return new google.maps.Point(a,b)},destroy:function(){this.repositionListener&&
2737 google.maps.event.removeListener(this.repositionListener);this.repositionTimer&&window.clearTimeout(this.repositionTimer);OpenLayers.Layer.Google.prototype.destroy.apply(this,arguments)}};OpenLayers.Format.WPSDescribeProcess=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{wps:"http://www.opengis.net/wps/1.0.0",ows:"http://www.opengis.net/ows/1.1",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wpsAll.xsd",defaultPrefix:"wps",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,
2738 [a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{wps:{ProcessDescriptions:function(a,b){b.processDescriptions={};this.readChildNodes(a,b.processDescriptions)},ProcessDescription:function(a,b){var c={processVersion:this.getAttributeNS(a,this.namespaces.wps,"processVersion"),statusSupported:"true"===a.getAttribute("statusSupported"),storeSupported:"true"===a.getAttribute("storeSupported")};this.readChildNodes(a,c);b[c.identifier]=c},DataInputs:function(a,
2739 b){b.dataInputs=[];this.readChildNodes(a,b.dataInputs)},ProcessOutputs:function(a,b){b.processOutputs=[];this.readChildNodes(a,b.processOutputs)},Output:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)},ComplexOutput:function(a,b){b.complexOutput={};this.readChildNodes(a,b.complexOutput)},Input:function(a,b){var c={maxOccurs:parseInt(a.getAttribute("maxOccurs")),minOccurs:parseInt(a.getAttribute("minOccurs"))};this.readChildNodes(a,c);b.push(c)},BoundingBoxData:function(a,b){b.boundingBoxData=
2740 {};this.readChildNodes(a,b.boundingBoxData)},CRS:function(a,b){b.CRSs||(b.CRSs={});b.CRSs[this.getChildValue(a)]=!0},LiteralData:function(a,b){b.literalData={};this.readChildNodes(a,b.literalData)},ComplexData:function(a,b){b.complexData={};this.readChildNodes(a,b.complexData)},Default:function(a,b){b["default"]={};this.readChildNodes(a,b["default"])},Supported:function(a,b){b.supported={};this.readChildNodes(a,b.supported)},Format:function(a,b){var c={};this.readChildNodes(a,c);b.formats||(b.formats=
2741 {});b.formats[c.mimeType]=!0},MimeType:function(a,b){b.mimeType=this.getChildValue(a)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSDescribeProcess"});OpenLayers.Format.CSWGetRecords.v2_0_2=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{csw:"http://www.opengis.net/cat/csw/2.0.2",dc:"http://purl.org/dc/elements/1.1/",dct:"http://purl.org/dc/terms/",gmd:"http://www.isotc211.org/2005/gmd",geonet:"http://www.fao.org/geonetwork",ogc:"http://www.opengis.net/ogc",ows:"http://www.opengis.net/ows",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"csw",version:"2.0.2",schemaLocation:"http://www.opengis.net/cat/csw/2.0.2 http://schemas.opengis.net/csw/2.0.2/CSW-discovery.xsd",
2742 requestId:null,resultType:null,outputFormat:null,outputSchema:null,startPosition:null,maxRecords:null,DistributedSearch:null,ResponseHandler:null,Query:null,regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},
2743 readers:{csw:{GetRecordsResponse:function(a,b){b.records=[];this.readChildNodes(a,b);var c=this.getAttributeNS(a,"","version");""!=c&&(b.version=c)},RequestId:function(a,b){b.RequestId=this.getChildValue(a)},SearchStatus:function(a,b){b.SearchStatus={};var c=this.getAttributeNS(a,"","timestamp");""!=c&&(b.SearchStatus.timestamp=c)},SearchResults:function(a,b){this.readChildNodes(a,b);for(var c=a.attributes,d={},e=0,f=c.length;e<f;++e)d[c[e].name]="numberOfRecordsMatched"==c[e].name||"numberOfRecordsReturned"==
2744 c[e].name||"nextRecord"==c[e].name?parseInt(c[e].nodeValue):c[e].nodeValue;b.SearchResults=d},SummaryRecord:function(a,b){var c={type:"SummaryRecord"};this.readChildNodes(a,c);b.records.push(c)},BriefRecord:function(a,b){var c={type:"BriefRecord"};this.readChildNodes(a,c);b.records.push(c)},DCMIRecord:function(a,b){var c={type:"DCMIRecord"};this.readChildNodes(a,c);b.records.push(c)},Record:function(a,b){var c={type:"Record"};this.readChildNodes(a,c);b.records.push(c)},"*":function(a,b){var c=a.localName||
2745 a.nodeName.split(":").pop();b[c]=this.getChildValue(a)}},geonet:{info:function(a,b){var c={};this.readChildNodes(a,c);b.gninfo=c}},dc:{"*":function(a,b){var c=a.localName||a.nodeName.split(":").pop();OpenLayers.Util.isArray(b[c])||(b[c]=[]);for(var d={},e=a.attributes,f=0,g=e.length;f<g;++f)d[e[f].name]=e[f].nodeValue;d.value=this.getChildValue(a);""!=d.value&&b[c].push(d)}},dct:{"*":function(a,b){var c=a.localName||a.nodeName.split(":").pop();OpenLayers.Util.isArray(b[c])||(b[c]=[]);b[c].push(this.getChildValue(a))}},
2746 ows:OpenLayers.Util.applyDefaults({BoundingBox:function(a,b){b.bounds&&(b.BoundingBox=[{crs:b.projection,value:[b.bounds.left,b.bounds.bottom,b.bounds.right,b.bounds.top]}],delete b.projection,delete b.bounds);OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows.BoundingBox.apply(this,arguments)}},OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows)},write:function(a){a=this.writeNode("csw:GetRecords",a);a.setAttribute("xmlns:gmd",this.namespaces.gmd);return OpenLayers.Format.XML.prototype.write.apply(this,
2747 [a])},writers:{csw:{GetRecords:function(a){a||(a={});var b=this.createElementNSPlus("csw:GetRecords",{attributes:{service:"CSW",version:this.version,requestId:a.requestId||this.requestId,resultType:a.resultType||this.resultType,outputFormat:a.outputFormat||this.outputFormat,outputSchema:a.outputSchema||this.outputSchema,startPosition:a.startPosition||this.startPosition,maxRecords:a.maxRecords||this.maxRecords}});if(a.DistributedSearch||this.DistributedSearch)this.writeNode("csw:DistributedSearch",
2748 a.DistributedSearch||this.DistributedSearch,b);var c=a.ResponseHandler||this.ResponseHandler;if(OpenLayers.Util.isArray(c)&&0<c.length)for(var d=0,e=c.length;d<e;d++)this.writeNode("csw:ResponseHandler",c[d],b);this.writeNode("Query",a.Query||this.Query,b);return b},DistributedSearch:function(a){return this.createElementNSPlus("csw:DistributedSearch",{attributes:{hopCount:a.hopCount}})},ResponseHandler:function(a){return this.createElementNSPlus("csw:ResponseHandler",{value:a.value})},Query:function(a){a||
2749 (a={});var b=this.createElementNSPlus("csw:Query",{attributes:{typeNames:a.typeNames||"csw:Record"}}),c=a.ElementName;if(OpenLayers.Util.isArray(c)&&0<c.length)for(var d=0,e=c.length;d<e;d++)this.writeNode("csw:ElementName",c[d],b);else this.writeNode("csw:ElementSetName",a.ElementSetName||{value:"summary"},b);a.Constraint&&this.writeNode("csw:Constraint",a.Constraint,b);a.SortBy&&this.writeNode("ogc:SortBy",a.SortBy,b);return b},ElementName:function(a){return this.createElementNSPlus("csw:ElementName",
2750 {value:a.value})},ElementSetName:function(a){return this.createElementNSPlus("csw:ElementSetName",{attributes:{typeNames:a.typeNames},value:a.value})},Constraint:function(a){var b=this.createElementNSPlus("csw:Constraint",{attributes:{version:a.version}});if(a.Filter){var c=new OpenLayers.Format.Filter({version:a.version});b.appendChild(c.write(a.Filter))}else a.CqlText&&(a=this.createElementNSPlus("CqlText",{value:a.CqlText.value}),b.appendChild(a));return b}},ogc:OpenLayers.Format.Filter.v1_1_0.prototype.writers.ogc},
2751 CLASS_NAME:"OpenLayers.Format.CSWGetRecords.v2_0_2"});OpenLayers.Marker.Box=OpenLayers.Class(OpenLayers.Marker,{bounds:null,div:null,initialize:function(a,b,c){this.bounds=a;this.div=OpenLayers.Util.createDiv();this.div.style.overflow="hidden";this.events=new OpenLayers.Events(this,this.div);this.setBorder(b,c)},destroy:function(){this.div=this.bounds=null;OpenLayers.Marker.prototype.destroy.apply(this,arguments)},setBorder:function(a,b){a||(a="red");b||(b=2);this.div.style.border=b+"px solid "+a},draw:function(a,b){OpenLayers.Util.modifyDOMElement(this.div,
2752 null,a,b);return this.div},onScreen:function(){var a=!1;this.map&&(a=this.map.getExtent().containsBounds(this.bounds,!0,!0));return a},display:function(a){this.div.style.display=a?"":"none"},CLASS_NAME:"OpenLayers.Marker.Box"});OpenLayers.Format.Text=OpenLayers.Class(OpenLayers.Format,{defaultStyle:null,extractStyles:!0,initialize:function(a){a=a||{};!1!==a.extractStyles&&(a.defaultStyle={externalGraphic:OpenLayers.Util.getImageLocation("marker.png"),graphicWidth:21,graphicHeight:25,graphicXOffset:-10.5,graphicYOffset:-12.5});OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){for(var a=a.split("\n"),b,c=[],d=0;d<a.length-1;d++){var e=a[d].replace(/^\s*/,"").replace(/\s*$/,"");if("#"!=e.charAt(0))if(b){for(var e=
2753 e.split("\t"),f=new OpenLayers.Geometry.Point(0,0),g={},h=this.defaultStyle?OpenLayers.Util.applyDefaults({},this.defaultStyle):null,i=!1,j=0;j<e.length;j++)if(e[j])if("point"==b[j])i=e[j].split(","),f.y=parseFloat(i[0]),f.x=parseFloat(i[1]),i=!0;else if("lat"==b[j])f.y=parseFloat(e[j]),i=!0;else if("lon"==b[j])f.x=parseFloat(e[j]),i=!0;else if("title"==b[j])g.title=e[j];else if("image"==b[j]||"icon"==b[j]&&h)h.externalGraphic=e[j];else if("iconSize"==b[j]&&h){var k=e[j].split(",");h.graphicWidth=
2754 parseFloat(k[0]);h.graphicHeight=parseFloat(k[1])}else"iconOffset"==b[j]&&h?(k=e[j].split(","),h.graphicXOffset=parseFloat(k[0]),h.graphicYOffset=parseFloat(k[1])):"description"==b[j]?g.description=e[j]:"overflow"==b[j]?g.overflow=e[j]:g[b[j]]=e[j];i&&(this.internalProjection&&this.externalProjection&&f.transform(this.externalProjection,this.internalProjection),e=new OpenLayers.Feature.Vector(f,g,h),c.push(e))}else b=e.split("\t")}return c},CLASS_NAME:"OpenLayers.Format.Text"});OpenLayers.Layer.Text=OpenLayers.Class(OpenLayers.Layer.Markers,{location:null,features:null,formatOptions:null,selectedFeature:null,initialize:function(a,b){OpenLayers.Layer.Markers.prototype.initialize.apply(this,arguments);this.features=[]},destroy:function(){OpenLayers.Layer.Markers.prototype.destroy.apply(this,arguments);this.clearFeatures();this.features=null},loadText:function(){!this.loaded&&null!=this.location&&(this.events.triggerEvent("loadstart"),OpenLayers.Request.GET({url:this.location,
2755 success:this.parseData,failure:function(){this.events.triggerEvent("loadend")},scope:this}),this.loaded=!0)},moveTo:function(a,b,c){OpenLayers.Layer.Markers.prototype.moveTo.apply(this,arguments);this.visibility&&!this.loaded&&this.loadText()},parseData:function(a){var a=a.responseText,b={};OpenLayers.Util.extend(b,this.formatOptions);this.map&&!this.projection.equals(this.map.getProjectionObject())&&(b.externalProjection=this.projection,b.internalProjection=this.map.getProjectionObject());for(var a=
2756 (new OpenLayers.Format.Text(b)).read(a),b=0,c=a.length;b<c;b++){var d={},e=a[b],f,g,h;f=new OpenLayers.LonLat(e.geometry.x,e.geometry.y);e.style.graphicWidth&&e.style.graphicHeight&&(g=new OpenLayers.Size(e.style.graphicWidth,e.style.graphicHeight));void 0!==e.style.graphicXOffset&&void 0!==e.style.graphicYOffset&&(h=new OpenLayers.Pixel(e.style.graphicXOffset,e.style.graphicYOffset));null!=e.style.externalGraphic?d.icon=new OpenLayers.Icon(e.style.externalGraphic,g,h):(d.icon=OpenLayers.Marker.defaultIcon(),
2757 null!=g&&d.icon.setSize(g));null!=e.attributes.title&&null!=e.attributes.description&&(d.popupContentHTML="<h2>"+e.attributes.title+"</h2><p>"+e.attributes.description+"</p>");d.overflow=e.attributes.overflow||"auto";d=new OpenLayers.Feature(this,f,d);this.features.push(d);f=d.createMarker();null!=e.attributes.title&&null!=e.attributes.description&&f.events.register("click",d,this.markerClick);this.addMarker(f)}this.events.triggerEvent("loadend")},markerClick:function(a){var b=this==this.layer.selectedFeature;
2758 this.layer.selectedFeature=!b?this:null;for(var c=0,d=this.layer.map.popups.length;c<d;c++)this.layer.map.removePopup(this.layer.map.popups[c]);b||this.layer.map.addPopup(this.createPopup());OpenLayers.Event.stop(a)},clearFeatures:function(){if(null!=this.features)for(;0<this.features.length;){var a=this.features[0];OpenLayers.Util.removeItem(this.features,a);a.destroy()}},CLASS_NAME:"OpenLayers.Layer.Text"});OpenLayers.Handler.RegularPolygon=OpenLayers.Class(OpenLayers.Handler.Drag,{sides:4,radius:null,snapAngle:null,snapToggle:"shiftKey",layerOptions:null,persist:!1,irregular:!1,citeCompliant:!1,angle:null,fixedRadius:!1,feature:null,layer:null,origin:null,initialize:function(a,b,c){if(!c||!c.layerOptions||!c.layerOptions.styleMap)this.style=OpenLayers.Util.extend(OpenLayers.Feature.Vector.style["default"],{});OpenLayers.Handler.Drag.prototype.initialize.apply(this,[a,b,c]);this.options=c?c:{}},setOptions:function(a){OpenLayers.Util.extend(this.options,
2759 a);OpenLayers.Util.extend(this,a)},activate:function(){var a=!1;OpenLayers.Handler.Drag.prototype.activate.apply(this,arguments)&&(a=OpenLayers.Util.extend({displayInLayerSwitcher:!1,calculateInRange:OpenLayers.Function.True,wrapDateLine:this.citeCompliant},this.layerOptions),this.layer=new OpenLayers.Layer.Vector(this.CLASS_NAME,a),this.map.addLayer(this.layer),a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.Drag.prototype.deactivate.apply(this,arguments)&&(this.dragging&&this.cancel(),
2760 null!=this.layer.map&&(this.layer.destroy(!1),this.feature&&this.feature.destroy()),this.feature=this.layer=null,a=!0);return a},down:function(a){this.fixedRadius=!!this.radius;a=this.layer.getLonLatFromViewPortPx(a.xy);this.origin=new OpenLayers.Geometry.Point(a.lon,a.lat);if(!this.fixedRadius||this.irregular)this.radius=this.map.getResolution();this.persist&&this.clear();this.feature=new OpenLayers.Feature.Vector;this.createGeometry();this.callback("create",[this.origin,this.feature]);this.layer.addFeatures([this.feature],
2761 {silent:!0});this.layer.drawFeature(this.feature,this.style)},move:function(a){var b=this.layer.getLonLatFromViewPortPx(a.xy),b=new OpenLayers.Geometry.Point(b.lon,b.lat);this.irregular?(a=Math.sqrt(2)*Math.abs(b.y-this.origin.y)/2,this.radius=Math.max(this.map.getResolution()/2,a)):this.fixedRadius?this.origin=b:(this.calculateAngle(b,a),this.radius=Math.max(this.map.getResolution()/2,b.distanceTo(this.origin)));this.modifyGeometry();this.irregular&&(a=b.x-this.origin.x,b=b.y-this.origin.y,this.feature.geometry.resize(1,
2762 this.origin,0==b?a/(this.radius*Math.sqrt(2)):a/b),this.feature.geometry.move(a/2,b/2));this.layer.drawFeature(this.feature,this.style)},up:function(a){this.finalize();this.start==this.last&&this.callback("done",[a.xy])},out:function(){this.finalize()},createGeometry:function(){this.angle=Math.PI*(1/this.sides-0.5);this.snapAngle&&(this.angle+=this.snapAngle*(Math.PI/180));this.feature.geometry=OpenLayers.Geometry.Polygon.createRegularPolygon(this.origin,this.radius,this.sides,this.snapAngle)},modifyGeometry:function(){var a,
2763 b,c=this.feature.geometry.components[0];c.components.length!=this.sides+1&&(this.createGeometry(),c=this.feature.geometry.components[0]);for(var d=0;d<this.sides;++d)b=c.components[d],a=this.angle+2*d*Math.PI/this.sides,b.x=this.origin.x+this.radius*Math.cos(a),b.y=this.origin.y+this.radius*Math.sin(a),b.clearBounds()},calculateAngle:function(a,b){var c=Math.atan2(a.y-this.origin.y,a.x-this.origin.x);if(this.snapAngle&&this.snapToggle&&!b[this.snapToggle]){var d=Math.PI/180*this.snapAngle;this.angle=
2764 Math.round(c/d)*d}else this.angle=c},cancel:function(){this.callback("cancel",null);this.finalize()},finalize:function(){this.origin=null;this.radius=this.options.radius},clear:function(){this.layer&&(this.layer.renderer.clear(),this.layer.destroyFeatures())},callback:function(a){this.callbacks[a]&&this.callbacks[a].apply(this.control,[this.feature.geometry.clone()]);!this.persist&&("done"==a||"cancel"==a)&&this.clear()},CLASS_NAME:"OpenLayers.Handler.RegularPolygon"});OpenLayers.Control.SLDSelect=OpenLayers.Class(OpenLayers.Control,{clearOnDeactivate:!1,layers:null,callbacks:null,selectionSymbolizer:{Polygon:{fillColor:"#FF0000",stroke:!1},Line:{strokeColor:"#FF0000",strokeWidth:2},Point:{graphicName:"square",fillColor:"#FF0000",pointRadius:5}},layerOptions:null,handlerOptions:null,sketchStyle:null,wfsCache:{},layerCache:{},initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.callbacks=OpenLayers.Util.extend({done:this.select,click:this.select},
2765 this.callbacks);this.handlerOptions=this.handlerOptions||{};this.layerOptions=OpenLayers.Util.applyDefaults(this.layerOptions,{displayInLayerSwitcher:!1,tileOptions:{maxGetUrlLength:2048}});this.sketchStyle&&(this.handlerOptions.layerOptions=OpenLayers.Util.applyDefaults(this.handlerOptions.layerOptions,{styleMap:new OpenLayers.StyleMap({"default":this.sketchStyle})}));this.handler=new a(this,this.callbacks,this.handlerOptions)},destroy:function(){for(var a in this.layerCache)delete this.layerCache[a];
2766 for(a in this.wfsCache)delete this.wfsCache[a];OpenLayers.Control.prototype.destroy.apply(this,arguments)},coupleLayerVisiblity:function(a){this.setVisibility(a.object.getVisibility())},createSelectionLayer:function(a){var b;if(this.layerCache[a.id])b=this.layerCache[a.id];else{b=new OpenLayers.Layer.WMS(a.name,a.url,a.params,OpenLayers.Util.applyDefaults(this.layerOptions,a.getOptions()));this.layerCache[a.id]=b;if(!1===this.layerOptions.displayInLayerSwitcher)a.events.on({visibilitychanged:this.coupleLayerVisiblity,
2767 scope:b});this.map.addLayer(b)}return b},createSLD:function(a,b,c){for(var d={version:"1.0.0",namedLayers:{}},e=(""+a.params.LAYERS).split(","),f=0,g=e.length;f<g;f++){var h=e[f];d.namedLayers[h]={name:h,userStyles:[]};var i=this.selectionSymbolizer,j=c[f];0<=j.type.indexOf("Polygon")?i={Polygon:this.selectionSymbolizer.Polygon}:0<=j.type.indexOf("LineString")?i={Line:this.selectionSymbolizer.Line}:0<=j.type.indexOf("Point")&&(i={Point:this.selectionSymbolizer.Point});d.namedLayers[h].userStyles.push({name:"default",
2768 rules:[new OpenLayers.Rule({symbolizer:i,filter:b[f],maxScaleDenominator:a.options.minScale})]})}return(new OpenLayers.Format.SLD({srsName:this.map.getProjection()})).write(d)},parseDescribeLayer:function(a){var b=new OpenLayers.Format.WMSDescribeLayer,c=a.responseXML;if(!c||!c.documentElement)c=a.responseText;for(var a=b.read(c),b=[],c=null,d=0,e=a.length;d<e;d++)"WFS"==a[d].owsType&&(b.push(a[d].typeName),c=a[d].owsURL);OpenLayers.Request.GET({url:c,params:{SERVICE:"WFS",TYPENAME:b.toString(),REQUEST:"DescribeFeatureType",
2769 VERSION:"1.0.0"},callback:function(a){var b=new OpenLayers.Format.WFSDescribeFeatureType,c=a.responseXML;if(!c||!c.documentElement)c=a.responseText;this.control.wfsCache[this.layer.id]=b.read(c);this.control._queue&&this.control.applySelection()},scope:this})},getGeometryAttributes:function(a){for(var b=[],a=this.wfsCache[a.id],c=0,d=a.featureTypes.length;c<d;c++)for(var e=a.featureTypes[c].properties,f=0,g=e.length;f<g;f++){var h=e[f],i=h.type;(0<=i.indexOf("LineString")||0<=i.indexOf("GeometryAssociationType")||
2770 0<=i.indexOf("GeometryPropertyType")||0<=i.indexOf("Point")||0<=i.indexOf("Polygon"))&&b.push(h)}return b},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a)for(var b=0,c=this.layers.length;b<c;b++){var d=this.layers[b];d&&!this.wfsCache[d.id]&&OpenLayers.Request.GET({url:d.url,params:{SERVICE:"WMS",VERSION:d.params.VERSION,LAYERS:d.params.LAYERS,REQUEST:"DescribeLayer"},callback:this.parseDescribeLayer,scope:{layer:d,control:this}})}return a},deactivate:function(){var a=
2771 OpenLayers.Control.prototype.deactivate.call(this);if(a)for(var b=0,c=this.layers.length;b<c;b++){var d=this.layers[b];if(d&&!0===this.clearOnDeactivate){var e=this.layerCache,f=e[d.id];f&&(d.events.un({visibilitychanged:this.coupleLayerVisiblity,scope:f}),f.destroy(),delete e[d.id])}}return a},setLayers:function(a){this.active?(this.deactivate(),this.layers=a,this.activate()):this.layers=a},createFilter:function(a,b){var c=null;this.handler instanceof OpenLayers.Handler.RegularPolygon?c=!0===this.handler.irregular?
2772 new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:a.name,value:b.getBounds()}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Polygon?c=new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Path?c=0<=a.type.indexOf("Point")?new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,
2773 property:a.name,distance:0.01*this.map.getExtent().getWidth(),distanceUnits:this.map.getUnits(),value:b}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):this.handler instanceof OpenLayers.Handler.Click&&(c=0<=a.type.indexOf("Polygon")?new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,property:a.name,value:b}):new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,property:a.name,distance:0.01*this.map.getExtent().getWidth(),
2774 distanceUnits:this.map.getUnits(),value:b}));return c},select:function(a){this._queue=function(){for(var b=0,c=this.layers.length;b<c;b++){for(var d=this.layers[b],e=this.getGeometryAttributes(d),f=[],g=0,h=e.length;g<h;g++){var i=e[g];if(null!==i){if(!(a instanceof OpenLayers.Geometry)){var j=this.map.getLonLatFromPixel(a.xy);a=new OpenLayers.Geometry.Point(j.lon,j.lat)}i=this.createFilter(i,a);null!==i&&f.push(i)}}g=this.createSelectionLayer(d);e=this.createSLD(d,f,e);this.events.triggerEvent("selected",
2775 {layer:d,filters:f});g.mergeNewParams({SLD_BODY:e});delete this._queue}};this.applySelection()},applySelection:function(){for(var a=!0,b=0,c=this.layers.length;b<c;b++)if(!this.wfsCache[this.layers[b].id]){a=!1;break}a&&this._queue.call(this)},CLASS_NAME:"OpenLayers.Control.SLDSelect"});OpenLayers.Control.Scale=OpenLayers.Class(OpenLayers.Control,{element:null,geodesic:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);this.element=OpenLayers.Util.getElement(a)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||(this.element=document.createElement("div"),this.div.appendChild(this.element));this.map.events.register("moveend",this,this.updateScale);this.updateScale();return this.div},updateScale:function(){var a;
2776 if(!0===this.geodesic){if(!this.map.getUnits())return;a=OpenLayers.INCHES_PER_UNIT;a=(this.map.getGeodesicPixelSize().w||1.0E-6)*a.km*OpenLayers.DOTS_PER_INCH}else a=this.map.getScale();a&&(a=9500<=a&&95E4>=a?Math.round(a/1E3)+"K":95E4<=a?Math.round(a/1E6)+"M":Math.round(a),this.element.innerHTML=OpenLayers.i18n("Scale = 1 : ${scaleDenom}",{scaleDenom:a}))},CLASS_NAME:"OpenLayers.Control.Scale"});OpenLayers.Control.Button=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_BUTTON,trigger:function(){},CLASS_NAME:"OpenLayers.Control.Button"});OpenLayers.Layer.MapGuide=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,useHttpTile:!1,singleTile:!1,useOverlay:!1,useAsyncOverlay:!0,TILE_PARAMS:{operation:"GETTILEIMAGE",version:"1.2.0"},SINGLE_TILE_PARAMS:{operation:"GETMAPIMAGE",format:"PNG",locale:"en",clip:"1",version:"1.0.0"},OVERLAY_PARAMS:{operation:"GETDYNAMICMAPOVERLAYIMAGE",format:"PNG",locale:"en",clip:"1",version:"2.0.0"},FOLDER_PARAMS:{tileColumnsPerFolder:30,tileRowsPerFolder:30,format:"png",querystring:null},defaultSize:new OpenLayers.Size(300,
2777 300),tileOriginCorner:"tl",initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);if(null==d||null==d.isBaseLayer)this.isBaseLayer="true"!=this.transparent&&!0!=this.transparent;d&&null!=d.useOverlay&&(this.useOverlay=d.useOverlay);this.singleTile?this.useOverlay?(OpenLayers.Util.applyDefaults(this.params,this.OVERLAY_PARAMS),this.useAsyncOverlay||(this.params.version="1.0.0")):OpenLayers.Util.applyDefaults(this.params,this.SINGLE_TILE_PARAMS):(this.useHttpTile?
2778 OpenLayers.Util.applyDefaults(this.params,this.FOLDER_PARAMS):OpenLayers.Util.applyDefaults(this.params,this.TILE_PARAMS),this.setTileSize(this.defaultSize))},clone:function(a){null==a&&(a=new OpenLayers.Layer.MapGuide(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var b;b=a.getCenterLonLat();var c=this.map.getSize();this.singleTile?(a={setdisplaydpi:OpenLayers.DOTS_PER_INCH,setdisplayheight:c.h*this.ratio,setdisplaywidth:c.w*
2779 this.ratio,setviewcenterx:b.lon,setviewcentery:b.lat,setviewscale:this.map.getScale()},this.useOverlay&&!this.useAsyncOverlay&&(b={},b=OpenLayers.Util.extend(b,a),b.operation="GETVISIBLEMAPEXTENT",b.version="1.0.0",b.session=this.params.session,b.mapName=this.params.mapName,b.format="text/xml",b=this.getFullRequestString(b),OpenLayers.Request.GET({url:b,async:!1})),b=this.getFullRequestString(a)):(c=this.map.getResolution(),b=Math.floor((a.left-this.maxExtent.left)/c),b=Math.round(b/this.tileSize.w),
2780 a=Math.floor((this.maxExtent.top-a.top)/c),a=Math.round(a/this.tileSize.h),b=this.useHttpTile?this.getImageFilePath({tilecol:b,tilerow:a,scaleindex:this.resolutions.length-this.map.zoom-1}):this.getFullRequestString({tilecol:b,tilerow:a,scaleindex:this.resolutions.length-this.map.zoom-1}));return b},getFullRequestString:function(a,b){var c=null==b?this.url:b;"object"==typeof c&&(c=c[Math.floor(Math.random()*c.length)]);var d=c,e=OpenLayers.Util.extend({},this.params),e=OpenLayers.Util.extend(e,a),
2781 f=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),g;for(g in e)g.toUpperCase()in f&&delete e[g];e=OpenLayers.Util.getParameterString(e);e=e.replace(/,/g,"+");""!=e&&(f=c.charAt(c.length-1),d="&"==f||"?"==f?d+e:-1==c.indexOf("?")?d+("?"+e):d+("&"+e));return d},getImageFilePath:function(a,b){var c=null==b?this.url:b;"object"==typeof c&&(c=c[Math.floor(Math.random()*c.length)]);var d="",e="";0>a.tilerow&&(d="-");d=0==a.tilerow?d+"0":d+Math.floor(Math.abs(a.tilerow/this.params.tileRowsPerFolder))*
2782 this.params.tileRowsPerFolder;0>a.tilecol&&(e="-");e=0==a.tilecol?e+"0":e+Math.floor(Math.abs(a.tilecol/this.params.tileColumnsPerFolder))*this.params.tileColumnsPerFolder;d="/S"+Math.floor(a.scaleindex)+"/"+this.params.basemaplayergroupname+"/R"+d+"/C"+e+"/"+a.tilerow%this.params.tileRowsPerFolder+"_"+a.tilecol%this.params.tileColumnsPerFolder+"."+this.params.format;this.params.querystring&&(d+="?"+this.params.querystring);return c+d},calculateGridLayout:function(a,b,c){var d=c*this.tileSize.w,c=
2783 c*this.tileSize.h,e=a.left-b.lon,f=Math.floor(e/d)-this.buffer,a=b.lat-a.top+c,g=Math.floor(a/c)-this.buffer;return{tilelon:d,tilelat:c,tileoffsetlon:b.lon+f*d,tileoffsetlat:b.lat-c*g,tileoffsetx:-(e/d-f)*this.tileSize.w,tileoffsety:(g-a/c)*this.tileSize.h}},CLASS_NAME:"OpenLayers.Layer.MapGuide"});OpenLayers.Control.Measure=OpenLayers.Class(OpenLayers.Control,{handlerOptions:null,callbacks:null,displaySystem:"metric",geodesic:!1,displaySystemUnits:{geographic:["dd"],english:["mi","ft","in"],metric:["km","m"]},partialDelay:300,delayedTrigger:null,persist:!1,immediate:!1,initialize:function(a,b){OpenLayers.Control.prototype.initialize.apply(this,[b]);var c={done:this.measureComplete,point:this.measurePartial};this.immediate&&(c.modify=this.measureImmediate);this.callbacks=OpenLayers.Util.extend(c,
2784 this.callbacks);this.handlerOptions=OpenLayers.Util.extend({persist:this.persist},this.handlerOptions);this.handler=new a(this,this.callbacks,this.handlerOptions)},deactivate:function(){this.cancelDelay();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},cancel:function(){this.cancelDelay();this.handler.cancel()},setImmediate:function(a){(this.immediate=a)?this.callbacks.modify=this.measureImmediate:delete this.callbacks.modify},updateHandler:function(a,b){var c=this.active;c&&
2785 this.deactivate();this.handler=new a(this,this.callbacks,b);c&&this.activate()},measureComplete:function(a){this.cancelDelay();this.measure(a,"measure")},measurePartial:function(a,b){this.cancelDelay();b=b.clone();this.handler.freehandMode(this.handler.evt)?this.measure(b,"measurepartial"):this.delayedTrigger=window.setTimeout(OpenLayers.Function.bind(function(){this.delayedTrigger=null;this.measure(b,"measurepartial")},this),this.partialDelay)},measureImmediate:function(a,b,c){c&&!this.handler.freehandMode(this.handler.evt)&&
2786 (this.cancelDelay(),this.measure(b.geometry,"measurepartial"))},cancelDelay:function(){null!==this.delayedTrigger&&(window.clearTimeout(this.delayedTrigger),this.delayedTrigger=null)},measure:function(a,b){var c,d;-1<a.CLASS_NAME.indexOf("LineString")?(c=this.getBestLength(a),d=1):(c=this.getBestArea(a),d=2);this.events.triggerEvent(b,{measure:c[0],units:c[1],order:d,geometry:a})},getBestArea:function(a){for(var b=this.displaySystemUnits[this.displaySystem],c,d,e=0,f=b.length;e<f&&!(c=b[e],d=this.getArea(a,
2787 c),1<d);++e);return[d,c]},getArea:function(a,b){var c,d;this.geodesic?(c=a.getGeodesicArea(this.map.getProjectionObject()),d="m"):(c=a.getArea(),d=this.map.getUnits());var e=OpenLayers.INCHES_PER_UNIT[b];e&&(c*=Math.pow(OpenLayers.INCHES_PER_UNIT[d]/e,2));return c},getBestLength:function(a){for(var b=this.displaySystemUnits[this.displaySystem],c,d,e=0,f=b.length;e<f&&!(c=b[e],d=this.getLength(a,c),1<d);++e);return[d,c]},getLength:function(a,b){var c,d;this.geodesic?(c=a.getGeodesicLength(this.map.getProjectionObject()),
2788 d="m"):(c=a.getLength(),d=this.map.getUnits());var e=OpenLayers.INCHES_PER_UNIT[b];e&&(c*=OpenLayers.INCHES_PER_UNIT[d]/e);return c},CLASS_NAME:"OpenLayers.Control.Measure"});OpenLayers.Format.WMC.v1_0_0=OpenLayers.Class(OpenLayers.Format.WMC.v1,{VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/context http://schemas.opengis.net/context/1.0.0/context.xsd",initialize:function(a){OpenLayers.Format.WMC.v1.prototype.initialize.apply(this,[a])},read_wmc_SRS:function(a,b){var c=this.getChildValue(b);"object"!=typeof a.projections&&(a.projections={});for(var c=c.split(/ +/),d=0,e=c.length;d<e;d++)a.projections[c[d]]=!0},write_wmc_Layer:function(a){var b=OpenLayers.Format.WMC.v1.prototype.write_wmc_Layer.apply(this,
2789 [a]);if(a.srs){var c=[],d;for(d in a.srs)c.push(d);b.appendChild(this.createElementDefaultNS("SRS",c.join(" ")))}b.appendChild(this.write_wmc_FormatList(a));b.appendChild(this.write_wmc_StyleList(a));a.dimensions&&b.appendChild(this.write_wmc_DimensionList(a));b.appendChild(this.write_wmc_LayerExtension(a))},CLASS_NAME:"OpenLayers.Format.WMC.v1_0_0"});OpenLayers.Popup.Framed=OpenLayers.Class(OpenLayers.Popup.Anchored,{imageSrc:null,imageSize:null,isAlphaImage:!1,positionBlocks:null,blocks:null,fixedRelativePosition:!1,initialize:function(a,b,c,d,e,f,g){OpenLayers.Popup.Anchored.prototype.initialize.apply(this,arguments);this.fixedRelativePosition&&(this.updateRelativePosition(),this.calculateRelativePosition=function(){return this.relativePosition});this.contentDiv.style.position="absolute";this.contentDiv.style.zIndex=1;f&&(this.closeDiv.style.zIndex=
2790 1);this.groupDiv.style.position="absolute";this.groupDiv.style.top="0px";this.groupDiv.style.left="0px";this.groupDiv.style.height="100%";this.groupDiv.style.width="100%"},destroy:function(){this.isAlphaImage=this.imageSize=this.imageSrc=null;this.fixedRelativePosition=!1;this.positionBlocks=null;for(var a=0;a<this.blocks.length;a++){var b=this.blocks[a];b.image&&b.div.removeChild(b.image);b.image=null;b.div&&this.groupDiv.removeChild(b.div);b.div=null}this.blocks=null;OpenLayers.Popup.Anchored.prototype.destroy.apply(this,
2791 arguments)},setBackgroundColor:function(){},setBorder:function(){},setOpacity:function(){},setSize:function(a){OpenLayers.Popup.Anchored.prototype.setSize.apply(this,arguments);this.updateBlocks()},updateRelativePosition:function(){this.padding=this.positionBlocks[this.relativePosition].padding;if(this.closeDiv){var a=this.getContentDivPadding();this.closeDiv.style.right=a.right+this.padding.right+"px";this.closeDiv.style.top=a.top+this.padding.top+"px"}this.updateBlocks()},calculateNewPx:function(a){var b=
2792 OpenLayers.Popup.Anchored.prototype.calculateNewPx.apply(this,arguments);return b=b.offset(this.positionBlocks[this.relativePosition].offset)},createBlocks:function(){this.blocks=[];var a=null,b;for(b in this.positionBlocks){a=b;break}a=this.positionBlocks[a];for(b=0;b<a.blocks.length;b++){var c={};this.blocks.push(c);c.div=OpenLayers.Util.createDiv(this.id+"_FrameDecorationDiv_"+b,null,null,null,"absolute",null,"hidden",null);c.image=(this.isAlphaImage?OpenLayers.Util.createAlphaImageDiv:OpenLayers.Util.createImage)(this.id+
2793 "_FrameDecorationImg_"+b,null,this.imageSize,this.imageSrc,"absolute",null,null,null);c.div.appendChild(c.image);this.groupDiv.appendChild(c.div)}},updateBlocks:function(){this.blocks||this.createBlocks();if(this.size&&this.relativePosition){for(var a=this.positionBlocks[this.relativePosition],b=0;b<a.blocks.length;b++){var c=a.blocks[b],d=this.blocks[b],e=c.anchor.left,f=c.anchor.bottom,g=c.anchor.right,h=c.anchor.top,i=isNaN(c.size.w)?this.size.w-(g+e):c.size.w,j=isNaN(c.size.h)?this.size.h-(f+
2794 h):c.size.h;d.div.style.width=(0>i?0:i)+"px";d.div.style.height=(0>j?0:j)+"px";d.div.style.left=null!=e?e+"px":"";d.div.style.bottom=null!=f?f+"px":"";d.div.style.right=null!=g?g+"px":"";d.div.style.top=null!=h?h+"px":"";d.image.style.left=c.position.x+"px";d.image.style.top=c.position.y+"px"}this.contentDiv.style.left=this.padding.left+"px";this.contentDiv.style.top=this.padding.top+"px"}},CLASS_NAME:"OpenLayers.Popup.Framed"});OpenLayers.Popup.FramedCloud=OpenLayers.Class(OpenLayers.Popup.Framed,{contentDisplayClass:"olFramedCloudPopupContent",autoSize:!0,panMapIfOutOfView:!0,imageSize:new OpenLayers.Size(1276,736),isAlphaImage:!1,fixedRelativePosition:!1,positionBlocks:{tl:{offset:new OpenLayers.Pixel(44,0),padding:new OpenLayers.Bounds(8,40,8,9),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,
2795 50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,18),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-632)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(0,-688)}]},tr:{offset:new OpenLayers.Pixel(-45,0),padding:new OpenLayers.Bounds(8,40,8,9),blocks:[{size:new OpenLayers.Size("auto",
2796 "auto"),anchor:new OpenLayers.Bounds(0,51,22,0),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,50,0,0),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",19),anchor:new OpenLayers.Bounds(0,32,22,null),position:new OpenLayers.Pixel(0,-631)},{size:new OpenLayers.Size(22,19),anchor:new OpenLayers.Bounds(null,32,0,null),position:new OpenLayers.Pixel(-1238,-631)},{size:new OpenLayers.Size(81,35),anchor:new OpenLayers.Bounds(0,
2797 0,null,null),position:new OpenLayers.Pixel(-215,-687)}]},bl:{offset:new OpenLayers.Pixel(45,0),padding:new OpenLayers.Bounds(8,9,8,40),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,0)},{size:new OpenLayers.Size("auto",21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,
2798 21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(null,null,0,0),position:new OpenLayers.Pixel(-101,-674)}]},br:{offset:new OpenLayers.Pixel(-44,0),padding:new OpenLayers.Bounds(8,9,8,40),blocks:[{size:new OpenLayers.Size("auto","auto"),anchor:new OpenLayers.Bounds(0,21,22,32),position:new OpenLayers.Pixel(0,0)},{size:new OpenLayers.Size(22,"auto"),anchor:new OpenLayers.Bounds(null,21,0,32),position:new OpenLayers.Pixel(-1238,
2799 0)},{size:new OpenLayers.Size("auto",21),anchor:new OpenLayers.Bounds(0,0,22,null),position:new OpenLayers.Pixel(0,-629)},{size:new OpenLayers.Size(22,21),anchor:new OpenLayers.Bounds(null,0,0,null),position:new OpenLayers.Pixel(-1238,-629)},{size:new OpenLayers.Size(81,33),anchor:new OpenLayers.Bounds(0,null,null,0),position:new OpenLayers.Pixel(-311,-674)}]}},minSize:new OpenLayers.Size(105,10),maxSize:new OpenLayers.Size(1200,660),initialize:function(a,b,c,d,e,f,g){this.imageSrc=OpenLayers.Util.getImageLocation("cloud-popup-relative.png");
2800 OpenLayers.Popup.Framed.prototype.initialize.apply(this,arguments);this.contentDiv.className=this.contentDisplayClass},CLASS_NAME:"OpenLayers.Popup.FramedCloud"});OpenLayers.Tile.Image.IFrame={useIFrame:null,draw:function(){if(OpenLayers.Tile.Image.prototype.shouldDraw.call(this)){var a=this.layer.getURL(this.bounds),b=this.useIFrame;this.useIFrame=null!==this.maxGetUrlLength&&!this.layer.async&&a.length>this.maxGetUrlLength;a=b&&!this.useIFrame;b=!b&&this.useIFrame;if(a||b)this.imgDiv&&this.imgDiv.parentNode===this.frame&&this.frame.removeChild(this.imgDiv),this.imgDiv=null,a?(this.blankImageUrl=this._blankImageUrl,this.frame.removeChild(this.frame.firstChild)):
2801 (this._blankImageUrl=this.blankImageUrl,this.blankImageUrl="about:blank")}return OpenLayers.Tile.Image.prototype.draw.apply(this,arguments)},getImage:function(){if(!0===this.useIFrame){if(!this.frame.childNodes.length){var a=document.createElement("div"),b=a.style;b.position="absolute";b.width="100%";b.height="100%";b.zIndex=1;b.backgroundImage="url("+this._blankImageUrl+")";this.frame.appendChild(a)}a=this.id+"_iFrame";9>parseFloat(navigator.appVersion.split("MSIE")[1])?(b=document.createElement('<iframe name="'+
2802 a+'">'),b.style.backgroundColor="#FFFFFF",b.style.filter="chroma(color=#FFFFFF)"):(b=document.createElement("iframe"),b.style.backgroundColor="transparent",b.name=a);b.scrolling="no";b.marginWidth="0px";b.marginHeight="0px";b.frameBorder="0";b.style.position="absolute";b.style.width="100%";b.style.height="100%";1>this.layer.opacity&&OpenLayers.Util.modifyDOMElement(b,null,null,null,null,null,null,this.layer.opacity);this.frame.appendChild(b);return this.imgDiv=b}return OpenLayers.Tile.Image.prototype.getImage.apply(this,
2803 arguments)},createRequestForm:function(){var a=document.createElement("form");a.method="POST";var b=this.layer.params._OLSALT,b=(b?b+"_":"")+this.bounds.toBBOX();a.action=OpenLayers.Util.urlAppend(this.layer.url,b);a.target=this.id+"_iFrame";this.layer.getImageSize();var b=OpenLayers.Util.getParameters(this.url),c,d;for(d in b)c=document.createElement("input"),c.type="hidden",c.name=d,c.value=b[d],a.appendChild(c);return a},setImgSrc:function(a){if(!0===this.useIFrame)if(a){var b=this.createRequestForm();
2804 this.frame.appendChild(b);b.submit();this.frame.removeChild(b)}else this.imgDiv.parentNode===this.frame&&(this.frame.removeChild(this.imgDiv),this.imgDiv=null);else OpenLayers.Tile.Image.prototype.setImgSrc.apply(this,arguments)},onImageLoad:function(){OpenLayers.Tile.Image.prototype.onImageLoad.apply(this,arguments);!0===this.useIFrame&&(this.imgDiv.style.opacity=1,this.frame.style.opacity=this.layer.opacity)},createBackBuffer:function(){var a;!1===this.useIFrame&&(a=OpenLayers.Tile.Image.prototype.createBackBuffer.call(this));
2805 return a}};OpenLayers.Format.SOSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.SOSCapabilities"});OpenLayers.Format.SOSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.SOSCapabilities,{namespaces:{ows:"http://www.opengis.net/ows/1.1",sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.options=a},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,
2806 [a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},readers:{gml:OpenLayers.Util.applyDefaults({name:function(a,b){b.name=this.getChildValue(a)},TimePeriod:function(a,b){b.timePeriod={};this.readChildNodes(a,b.timePeriod)},beginPosition:function(a,b){b.beginPosition=this.getChildValue(a)},endPosition:function(a,b){b.endPosition=this.getChildValue(a)}},OpenLayers.Format.GML.v3.prototype.readers.gml),sos:{Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,
2807 b){b.contents={};this.readChildNodes(a,b.contents)},ObservationOfferingList:function(a,b){b.offeringList={};this.readChildNodes(a,b.offeringList)},ObservationOffering:function(a,b){var c=this.getAttributeNS(a,this.namespaces.gml,"id");b[c]={procedures:[],observedProperties:[],featureOfInterestIds:[],responseFormats:[],resultModels:[],responseModes:[]};this.readChildNodes(a,b[c])},time:function(a,b){b.time={};this.readChildNodes(a,b.time)},procedure:function(a,b){b.procedures.push(this.getAttributeNS(a,
2808 this.namespaces.xlink,"href"))},observedProperty:function(a,b){b.observedProperties.push(this.getAttributeNS(a,this.namespaces.xlink,"href"))},featureOfInterest:function(a,b){b.featureOfInterestIds.push(this.getAttributeNS(a,this.namespaces.xlink,"href"))},responseFormat:function(a,b){b.responseFormats.push(this.getChildValue(a))},resultModel:function(a,b){b.resultModels.push(this.getChildValue(a))},responseMode:function(a,b){b.responseModes.push(this.getChildValue(a))}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},
2809 CLASS_NAME:"OpenLayers.Format.SOSCapabilities.v1_0_0"});OpenLayers.Handler.Pinch=OpenLayers.Class(OpenLayers.Handler,{started:!1,stopDown:!1,pinching:!1,last:null,start:null,touchstart:function(a){var b=!0;this.pinching=!1;OpenLayers.Event.isMultiTouch(a)?(this.started=!0,this.last=this.start={distance:this.getDistance(a.touches),delta:0,scale:1},this.callback("start",[a,this.start]),b=!this.stopDown):(this.started=!1,this.last=this.start=null);OpenLayers.Event.stop(a);return b},touchmove:function(a){if(this.started&&OpenLayers.Event.isMultiTouch(a)){this.pinching=
2810 !0;var b=this.getPinchData(a);this.callback("move",[a,b]);this.last=b;OpenLayers.Event.stop(a)}return!0},touchend:function(a){this.started&&(this.pinching=this.started=!1,this.callback("done",[a,this.start,this.last]),this.last=this.start=null);return!0},activate:function(){var a=!1;OpenLayers.Handler.prototype.activate.apply(this,arguments)&&(this.pinching=!1,a=!0);return a},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.pinching=this.started=
2811 !1,this.last=this.start=null,a=!0);return a},getDistance:function(a){var b=a[0],a=a[1];return Math.sqrt(Math.pow(b.clientX-a.clientX,2)+Math.pow(b.clientY-a.clientY,2))},getPinchData:function(a){a=this.getDistance(a.touches);return{distance:a,delta:this.last.distance-a,scale:a/this.start.distance}},CLASS_NAME:"OpenLayers.Handler.Pinch"});OpenLayers.Control.NavToolbar=OpenLayers.Class(OpenLayers.Control.Panel,{initialize:function(a){OpenLayers.Control.Panel.prototype.initialize.apply(this,[a]);this.addControls([new OpenLayers.Control.Navigation,new OpenLayers.Control.ZoomBox])},draw:function(){var a=OpenLayers.Control.Panel.prototype.draw.apply(this,arguments);null===this.defaultControl&&(this.defaultControl=this.controls[0]);return a},CLASS_NAME:"OpenLayers.Control.NavToolbar"});OpenLayers.Strategy.Refresh=OpenLayers.Class(OpenLayers.Strategy,{force:!1,interval:0,timer:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);a&&(!0===this.layer.visibility&&this.start(),this.layer.events.on({visibilitychanged:this.reset,scope:this}));return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&this.stop();return a},reset:function(){!0===this.layer.visibility?this.start():this.stop()},start:function(){this.interval&&("number"===
2812 typeof this.interval&&0<this.interval)&&(this.timer=window.setInterval(OpenLayers.Function.bind(this.refresh,this),this.interval))},refresh:function(){this.layer&&(this.layer.refresh&&"function"==typeof this.layer.refresh)&&this.layer.refresh({force:this.force})},stop:function(){null!==this.timer&&(window.clearInterval(this.timer),this.timer=null)},CLASS_NAME:"OpenLayers.Strategy.Refresh"});OpenLayers.Layer.ArcGIS93Rest=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{format:"png"},isBaseLayer:!0,initialize:function(a,b,c,d){var e=[],c=OpenLayers.Util.upperCaseObject(c);e.push(a,b,c,d);OpenLayers.Layer.Grid.prototype.initialize.apply(this,e);OpenLayers.Util.applyDefaults(this.params,OpenLayers.Util.upperCaseObject(this.DEFAULT_PARAMS));if(this.params.TRANSPARENT&&"true"==this.params.TRANSPARENT.toString().toLowerCase()){if(null==d||!d.isBaseLayer)this.isBaseLayer=!1;"jpg"==this.params.FORMAT&&
2813 (this.params.FORMAT=OpenLayers.Util.alphaHack()?"gif":"png")}},clone:function(a){null==a&&(a=new OpenLayers.Layer.ArcGIS93Rest(this.name,this.url,this.params,this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var a=this.adjustBounds(a),b=this.projection.getCode().split(":"),b=b[b.length-1],c=this.getImageSize(),a={BBOX:a.toBBOX(),SIZE:c.w+","+c.h,F:"image",BBOXSR:b,IMAGESR:b};if(this.layerDefs){var b=[],d;for(d in this.layerDefs)this.layerDefs.hasOwnProperty(d)&&
2814 this.layerDefs[d]&&(b.push(d),b.push(":"),b.push(this.layerDefs[d]),b.push(";"));0<b.length&&(a.LAYERDEFS=b.join(""))}return this.getFullRequestString(a)},setLayerFilter:function(a,b){this.layerDefs||(this.layerDefs={});b?this.layerDefs[a]=b:delete this.layerDefs[a]},clearLayerFilter:function(a){a?delete this.layerDefs[a]:delete this.layerDefs},mergeNewParams:function(a){a=[OpenLayers.Util.upperCaseObject(a)];return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,a)},CLASS_NAME:"OpenLayers.Layer.ArcGIS93Rest"});OpenLayers.Format.WKT=OpenLayers.Class(OpenLayers.Format,{initialize:function(a){this.regExes={typeStr:/^\s*(\w+)\s*\(\s*(.*)\s*\)\s*$/,spaces:/\s+/,parenComma:/\)\s*,\s*\(/,doubleParenComma:/\)\s*\)\s*,\s*\(\s*\(/,trimParens:/^\s*\(?(.*?)\)?\s*$/};OpenLayers.Format.prototype.initialize.apply(this,[a])},read:function(a){var b,c,a=a.replace(/[\n\r]/g," ");if(c=this.regExes.typeStr.exec(a))if(a=c[1].toLowerCase(),c=c[2],this.parse[a]&&(b=this.parse[a].apply(this,[c])),this.internalProjection&&this.externalProjection)if(b&&
2815 "OpenLayers.Feature.Vector"==b.CLASS_NAME)b.geometry.transform(this.externalProjection,this.internalProjection);else if(b&&"geometrycollection"!=a&&"object"==typeof b){a=0;for(c=b.length;a<c;a++)b[a].geometry.transform(this.externalProjection,this.internalProjection)}return b},write:function(a){var b,c;a.constructor==Array?c=!0:(a=[a],c=!1);var d=[];c&&d.push("GEOMETRYCOLLECTION(");for(var e=0,f=a.length;e<f;++e)c&&0<e&&d.push(","),b=a[e].geometry,d.push(this.extractGeometry(b));c&&d.push(")");return d.join("")},
2816 extractGeometry:function(a){var b=a.CLASS_NAME.split(".")[2].toLowerCase();if(!this.extract[b])return null;this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));return("collection"==b?"GEOMETRYCOLLECTION":b.toUpperCase())+"("+this.extract[b].apply(this,[a])+")"},extract:{point:function(a){return a.x+" "+a.y},multipoint:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.point.apply(this,[a.components[c]])+
2817 ")");return b.join(",")},linestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extract.point.apply(this,[a.components[c]]));return b.join(",")},multilinestring:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.linestring.apply(this,[a.components[c]])+")");return b.join(",")},polygon:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.linestring.apply(this,[a.components[c]])+")");return b.join(",")},multipolygon:function(a){for(var b=
2818 [],c=0,d=a.components.length;c<d;++c)b.push("("+this.extract.polygon.apply(this,[a.components[c]])+")");return b.join(",")},collection:function(a){for(var b=[],c=0,d=a.components.length;c<d;++c)b.push(this.extractGeometry.apply(this,[a.components[c]]));return b.join(",")}},parse:{point:function(a){a=OpenLayers.String.trim(a).split(this.regExes.spaces);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(a[0],a[1]))},multipoint:function(a){for(var b=OpenLayers.String.trim(a).split(","),
2819 c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.point.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPoint(c))},linestring:function(a){for(var a=OpenLayers.String.trim(a).split(","),b=[],c=0,d=a.length;c<d;++c)b.push(this.parse.point.apply(this,[a[c]]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(b))},multilinestring:function(a){for(var b=OpenLayers.String.trim(a).split(this.regExes.parenComma),
2820 c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.linestring.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiLineString(c))},polygon:function(a){for(var b,a=OpenLayers.String.trim(a).split(this.regExes.parenComma),c=[],d=0,e=a.length;d<e;++d)b=a[d].replace(this.regExes.trimParens,"$1"),b=this.parse.linestring.apply(this,[b]).geometry,b=new OpenLayers.Geometry.LinearRing(b.components),c.push(b);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Polygon(c))},
2821 multipolygon:function(a){for(var b=OpenLayers.String.trim(a).split(this.regExes.doubleParenComma),c=[],d=0,e=b.length;d<e;++d)a=b[d].replace(this.regExes.trimParens,"$1"),c.push(this.parse.polygon.apply(this,[a]).geometry);return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPolygon(c))},geometrycollection:function(a){for(var a=a.replace(/,\s*([A-Za-z])/g,"|$1"),a=OpenLayers.String.trim(a).split("|"),b=[],c=0,d=a.length;c<d;++c)b.push(OpenLayers.Format.WKT.prototype.read.apply(this,[a[c]]));
2822 return b}},CLASS_NAME:"OpenLayers.Format.WKT"});OpenLayers.Handler.Hover=OpenLayers.Class(OpenLayers.Handler,{delay:500,pixelTolerance:null,stopMove:!1,px:null,timerId:null,mousemove:function(a){this.passesTolerance(a.xy)&&(this.clearTimer(),this.callback("move",[a]),this.px=a.xy,a=OpenLayers.Util.extend({},a),this.timerId=window.setTimeout(OpenLayers.Function.bind(this.delayedCall,this,a),this.delay));return!this.stopMove},mouseout:function(a){OpenLayers.Util.mouseLeft(a,this.map.viewPortDiv)&&(this.clearTimer(),this.callback("move",[a]));return!0},
2823 passesTolerance:function(a){var b=!0;this.pixelTolerance&&this.px&&Math.sqrt(Math.pow(this.px.x-a.x,2)+Math.pow(this.px.y-a.y,2))<this.pixelTolerance&&(b=!1);return b},clearTimer:function(){null!=this.timerId&&(window.clearTimeout(this.timerId),this.timerId=null)},delayedCall:function(a){this.callback("pause",[a])},deactivate:function(){var a=!1;OpenLayers.Handler.prototype.deactivate.apply(this,arguments)&&(this.clearTimer(),a=!0);return a},CLASS_NAME:"OpenLayers.Handler.Hover"});OpenLayers.Control.GetFeature=OpenLayers.Class(OpenLayers.Control,{protocol:null,multipleKey:null,toggleKey:null,modifiers:null,multiple:!1,click:!0,single:!0,clickout:!0,toggle:!1,clickTolerance:5,hover:!1,box:!1,maxFeatures:10,features:null,hoverFeature:null,handlerOptions:null,handlers:null,hoverResponse:null,filterType:OpenLayers.Filter.Spatial.BBOX,initialize:function(a){a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.features={};this.handlers=
2824 {};this.click&&(this.handlers.click=new OpenLayers.Handler.Click(this,{click:this.selectClick},this.handlerOptions.click||{}));this.box&&(this.handlers.box=new OpenLayers.Handler.Box(this,{done:this.selectBox},OpenLayers.Util.extend(this.handlerOptions.box,{boxDivClassName:"olHandlerBoxSelectFeature"})));this.hover&&(this.handlers.hover=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.selectHover},OpenLayers.Util.extend(this.handlerOptions.hover,{delay:250,pixelTolerance:2})))},
2825 activate:function(){if(!this.active)for(var a in this.handlers)this.handlers[a].activate();return OpenLayers.Control.prototype.activate.apply(this,arguments)},deactivate:function(){if(this.active)for(var a in this.handlers)this.handlers[a].deactivate();return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},selectClick:function(a){var b=this.pixelToBounds(a.xy);this.setModifiers(a);this.request(b,{single:this.single})},selectBox:function(a){var b;if(a instanceof OpenLayers.Bounds)b=
2826 this.map.getLonLatFromPixel({x:a.left,y:a.bottom}),a=this.map.getLonLatFromPixel({x:a.right,y:a.top}),b=new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat);else{if(this.click)return;b=this.pixelToBounds(a)}this.setModifiers(this.handlers.box.dragHandler.evt);this.request(b)},selectHover:function(a){this.request(this.pixelToBounds(a.xy),{single:!0,hover:!0})},cancelHover:function(){this.hoverResponse&&(this.protocol.abort(this.hoverResponse),this.hoverResponse=null,OpenLayers.Element.removeClass(this.map.viewPortDiv,
2827 "olCursorWait"))},request:function(a,b){var b=b||{},c=new OpenLayers.Filter.Spatial({type:this.filterType,value:a});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");c=this.protocol.read({maxFeatures:!0==b.single?this.maxFeatures:void 0,filter:c,callback:function(c){c.success()&&(c.features.length?!0==b.single?this.selectBestFeature(c.features,a.getCenterLonLat(),b):this.select(c.features):b.hover?this.hoverSelect():(this.events.triggerEvent("clickout"),this.clickout&&this.unselectAll()));
2828 OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait")},scope:this});!0==b.hover&&(this.hoverResponse=c)},selectBestFeature:function(a,b,c){c=c||{};if(a.length){for(var b=new OpenLayers.Geometry.Point(b.lon,b.lat),d,e,f,g=Number.MAX_VALUE,h=0;h<a.length&&!(d=a[h],d.geometry&&(f=b.distanceTo(d.geometry,{edge:!1}),f<g&&(g=f,e=d,0==g)));++h);!0==c.hover?this.hoverSelect(e):this.select(e||a)}},setModifiers:function(a){this.modifiers={multiple:this.multiple||this.multipleKey&&a[this.multipleKey],
2829 toggle:this.toggle||this.toggleKey&&a[this.toggleKey]}},select:function(a){!this.modifiers.multiple&&!this.modifiers.toggle&&this.unselectAll();OpenLayers.Util.isArray(a)||(a=[a]);var b=this.events.triggerEvent("beforefeaturesselected",{features:a});if(!1!==b){for(var c=[],d,e=0,f=a.length;e<f;++e)d=a[e],this.features[d.fid||d.id]?this.modifiers.toggle&&this.unselect(this.features[d.fid||d.id]):(b=this.events.triggerEvent("beforefeatureselected",{feature:d}),!1!==b&&(this.features[d.fid||d.id]=d,
2830 c.push(d),this.events.triggerEvent("featureselected",{feature:d})));this.events.triggerEvent("featuresselected",{features:c})}},hoverSelect:function(a){var b=a?a.fid||a.id:null,c=this.hoverFeature?this.hoverFeature.fid||this.hoverFeature.id:null;c&&c!=b&&(this.events.triggerEvent("outfeature",{feature:this.hoverFeature}),this.hoverFeature=null);b&&b!=c&&(this.events.triggerEvent("hoverfeature",{feature:a}),this.hoverFeature=a)},unselect:function(a){delete this.features[a.fid||a.id];this.events.triggerEvent("featureunselected",
2831 {feature:a})},unselectAll:function(){for(var a in this.features)this.unselect(this.features[a])},setMap:function(a){for(var b in this.handlers)this.handlers[b].setMap(a);OpenLayers.Control.prototype.setMap.apply(this,arguments)},pixelToBounds:function(a){var b=a.add(-this.clickTolerance/2,this.clickTolerance/2),a=a.add(this.clickTolerance/2,-this.clickTolerance/2),b=this.map.getLonLatFromPixel(b),a=this.map.getLonLatFromPixel(a);return new OpenLayers.Bounds(b.lon,b.lat,a.lon,a.lat)},CLASS_NAME:"OpenLayers.Control.GetFeature"});OpenLayers.Format.QueryStringFilter=function(){function a(a){a=a.replace(/%/g,"\\%");a=a.replace(/\\\\\.(\*)?/g,function(a,b){return b?a:"\\\\_"});a=a.replace(/\\\\\.\*/g,"\\\\%");a=a.replace(/(\\)?\.(\*)?/g,function(a,b,c){return b||c?a:"_"});a=a.replace(/(\\)?\.\*/g,function(a,b){return b?a:"%"});a=a.replace(/\\\./g,".");return a=a.replace(/(\\)?\\\*/g,function(a,b){return b?a:"*"})}var b={};b[OpenLayers.Filter.Comparison.EQUAL_TO]="eq";b[OpenLayers.Filter.Comparison.NOT_EQUAL_TO]="ne";b[OpenLayers.Filter.Comparison.LESS_THAN]=
2832 "lt";b[OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO]="lte";b[OpenLayers.Filter.Comparison.GREATER_THAN]="gt";b[OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO]="gte";b[OpenLayers.Filter.Comparison.LIKE]="ilike";return OpenLayers.Class(OpenLayers.Format,{wildcarded:!1,srsInBBOX:!1,write:function(c,d){var d=d||{},e=c.CLASS_NAME,e=e.substring(e.lastIndexOf(".")+1);switch(e){case "Spatial":switch(c.type){case OpenLayers.Filter.Spatial.BBOX:d.bbox=c.value.toArray();this.srsInBBOX&&c.projection&&
2833 d.bbox.push(c.projection.getCode());break;case OpenLayers.Filter.Spatial.DWITHIN:d.tolerance=c.distance;case OpenLayers.Filter.Spatial.WITHIN:d.lon=c.value.x;d.lat=c.value.y;break;default:OpenLayers.Console.warn("Unknown spatial filter type "+c.type)}break;case "Comparison":e=b[c.type];if(void 0!==e){var f=c.value;c.type==OpenLayers.Filter.Comparison.LIKE&&(f=a(f),this.wildcarded&&(f="%"+f+"%"));d[c.property+"__"+e]=f;d.queryable=d.queryable||[];d.queryable.push(c.property)}else OpenLayers.Console.warn("Unknown comparison filter type "+
2834 c.type);break;case "Logical":if(c.type===OpenLayers.Filter.Logical.AND){e=0;for(f=c.filters.length;e<f;e++)d=this.write(c.filters[e],d)}else OpenLayers.Console.warn("Unsupported logical filter type "+c.type);break;default:OpenLayers.Console.warn("Unknown filter type "+e)}return d},CLASS_NAME:"OpenLayers.Format.QueryStringFilter"})}();OpenLayers.Control.MousePosition=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,element:null,prefix:"",separator:", ",suffix:"",numDigits:5,granularity:10,emptyString:null,lastXy:null,displayProjection:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.map.events.register("mousemove",this,this.redraw),this.map.events.register("mouseout",this,this.reset),
2835 this.redraw(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments)?(this.map.events.unregister("mousemove",this,this.redraw),this.map.events.unregister("mouseout",this,this.reset),this.element.innerHTML="",!0):!1},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.element||(this.div.left="",this.div.top="",this.element=this.div);return this.div},redraw:function(a){var b;if(null==a)this.reset();else if(null==this.lastXy||Math.abs(a.xy.x-
2836 this.lastXy.x)>this.granularity||Math.abs(a.xy.y-this.lastXy.y)>this.granularity)this.lastXy=a.xy;else if(b=this.map.getLonLatFromPixel(a.xy))this.displayProjection&&b.transform(this.map.getProjectionObject(),this.displayProjection),this.lastXy=a.xy,a=this.formatOutput(b),a!=this.element.innerHTML&&(this.element.innerHTML=a)},reset:function(){null!=this.emptyString&&(this.element.innerHTML=this.emptyString)},formatOutput:function(a){var b=parseInt(this.numDigits);return this.prefix+a.lon.toFixed(b)+
2837 this.separator+a.lat.toFixed(b)+this.suffix},CLASS_NAME:"OpenLayers.Control.MousePosition"});OpenLayers.Control.Geolocate=OpenLayers.Class(OpenLayers.Control,{geolocation:navigator.geolocation,bind:!0,watch:!1,geolocationOptions:null,destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments)},activate:function(){return!this.geolocation?(this.events.triggerEvent("locationuncapable"),!1):OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.watch?this.watchId=this.geolocation.watchPosition(OpenLayers.Function.bind(this.geolocate,this),OpenLayers.Function.bind(this.failure,
2838 this),this.geolocationOptions):this.getCurrentLocation(),!0):!1},deactivate:function(){this.active&&null!==this.watchId&&this.geolocation.clearWatch(this.watchId);return OpenLayers.Control.prototype.deactivate.apply(this,arguments)},geolocate:function(a){var b=(new OpenLayers.LonLat(a.coords.longitude,a.coords.latitude)).transform(new OpenLayers.Projection("EPSG:4326"),this.map.getProjectionObject());this.bind&&this.map.setCenter(b);this.events.triggerEvent("locationupdated",{position:a,point:new OpenLayers.Geometry.Point(b.lon,
2839 b.lat)})},getCurrentLocation:function(){if(!this.active||this.watch)return!1;this.geolocation.getCurrentPosition(OpenLayers.Function.bind(this.geolocate,this),OpenLayers.Function.bind(this.failure,this),this.geolocationOptions);return!0},failure:function(a){this.events.triggerEvent("locationfailed",{error:a})},CLASS_NAME:"OpenLayers.Control.Geolocate"});OpenLayers.Tile.UTFGrid=OpenLayers.Class(OpenLayers.Tile,{url:null,utfgridResolution:2,json:null,format:null,destroy:function(){this.clear();OpenLayers.Tile.prototype.destroy.apply(this,arguments)},draw:function(){var a=OpenLayers.Tile.prototype.draw.apply(this,arguments);if(a)if(this.isLoading?(this.abortLoading(),this.events.triggerEvent("reload")):(this.isLoading=!0,this.events.triggerEvent("loadstart")),this.url=this.layer.getURL(this.bounds),this.layer.useJSONP){var b=new OpenLayers.Protocol.Script({url:this.url,
2840 callback:function(a){this.isLoading=false;this.events.triggerEvent("loadend");this.json=a.data},scope:this});b.read();this.request=b}else this.request=OpenLayers.Request.GET({url:this.url,callback:function(a){this.isLoading=false;this.events.triggerEvent("loadend");a.status===200&&this.parseData(a.responseText)},scope:this});else this.unload();return a},abortLoading:function(){this.request&&(this.request.abort(),delete this.request);this.isLoading=!1},getFeatureInfo:function(a,b){var c=null;if(this.json){var d=
2841 this.getFeatureId(a,b);null!==d&&(c={id:d,data:this.json.data[d]})}return c},getFeatureId:function(a,b){var c=null;if(this.json){var d=this.utfgridResolution,d=this.indexFromCharCode(this.json.grid[Math.floor(b/d)].charCodeAt(Math.floor(a/d))),e=this.json.keys;!isNaN(d)&&d in e&&(c=e[d])}return c},indexFromCharCode:function(a){93<=a&&a--;35<=a&&a--;return a-32},parseData:function(a){this.format||(this.format=new OpenLayers.Format.JSON);this.json=this.format.read(a)},clear:function(){this.json=null},
2842 CLASS_NAME:"OpenLayers.Tile.UTFGrid"});OpenLayers.Control.NavigationHistory=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOGGLE,previous:null,previousOptions:null,next:null,nextOptions:null,limit:50,autoActivate:!0,clearOnDeactivate:!1,registry:null,nextStack:null,previousStack:null,listeners:null,restoring:!1,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.registry=OpenLayers.Util.extend({moveend:this.getState},this.registry);a={trigger:OpenLayers.Function.bind(this.previousTrigger,
2843 this),displayClass:this.displayClass+" "+this.displayClass+"Previous"};OpenLayers.Util.extend(a,this.previousOptions);this.previous=new OpenLayers.Control.Button(a);a={trigger:OpenLayers.Function.bind(this.nextTrigger,this),displayClass:this.displayClass+" "+this.displayClass+"Next"};OpenLayers.Util.extend(a,this.nextOptions);this.next=new OpenLayers.Control.Button(a);this.clear()},onPreviousChange:function(a){a&&!this.previous.active?this.previous.activate():!a&&this.previous.active&&this.previous.deactivate()},
2844 onNextChange:function(a){a&&!this.next.active?this.next.activate():!a&&this.next.active&&this.next.deactivate()},destroy:function(){OpenLayers.Control.prototype.destroy.apply(this);this.previous.destroy();this.next.destroy();this.deactivate();for(var a in this)this[a]=null},setMap:function(a){this.map=a;this.next.setMap(a);this.previous.setMap(a)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);this.next.draw();this.previous.draw()},previousTrigger:function(){var a=this.previousStack.shift(),
2845 b=this.previousStack.shift();void 0!=b?(this.nextStack.unshift(a),this.previousStack.unshift(b),this.restoring=!0,this.restore(b),this.restoring=!1,this.onNextChange(this.nextStack[0],this.nextStack.length),this.onPreviousChange(this.previousStack[1],this.previousStack.length-1)):this.previousStack.unshift(a);return b},nextTrigger:function(){var a=this.nextStack.shift();void 0!=a&&(this.previousStack.unshift(a),this.restoring=!0,this.restore(a),this.restoring=!1,this.onNextChange(this.nextStack[0],
2846 this.nextStack.length),this.onPreviousChange(this.previousStack[1],this.previousStack.length-1));return a},clear:function(){this.previousStack=[];this.previous.deactivate();this.nextStack=[];this.next.deactivate()},getState:function(){return{center:this.map.getCenter(),resolution:this.map.getResolution(),projection:this.map.getProjectionObject(),units:this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units}},restore:function(a){var b,c;if(this.map.getProjectionObject()==
2847 a.projection)c=this.map.getZoomForResolution(a.resolution),b=a.center;else{b=a.center.clone();b.transform(a.projection,this.map.getProjectionObject());c=a.units;var d=this.map.getProjectionObject().getUnits()||this.map.units||this.map.baseLayer.units;c=this.map.getZoomForResolution((c&&d?OpenLayers.INCHES_PER_UNIT[c]/OpenLayers.INCHES_PER_UNIT[d]:1)*a.resolution)}this.map.setCenter(b,c)},setListeners:function(){this.listeners={};for(var a in this.registry)this.listeners[a]=OpenLayers.Function.bind(function(){if(!this.restoring){this.previousStack.unshift(this.registry[a].apply(this,
2848 arguments));if(1<this.previousStack.length)this.onPreviousChange(this.previousStack[1],this.previousStack.length-1);this.previousStack.length>this.limit+1&&this.previousStack.pop();0<this.nextStack.length&&(this.nextStack=[],this.onNextChange(null,0))}return!0},this)},activate:function(){var a=!1;if(this.map&&OpenLayers.Control.prototype.activate.apply(this)){null==this.listeners&&this.setListeners();for(var b in this.listeners)this.map.events.register(b,this,this.listeners[b]);a=!0;0==this.previousStack.length&&
2849 this.initStack()}return a},initStack:function(){this.map.getCenter()&&this.listeners.moveend()},deactivate:function(){var a=!1;if(this.map&&OpenLayers.Control.prototype.deactivate.apply(this)){for(var b in this.listeners)this.map.events.unregister(b,this,this.listeners[b]);this.clearOnDeactivate&&this.clear();a=!0}return a},CLASS_NAME:"OpenLayers.Control.NavigationHistory"});OpenLayers.Protocol.HTTP=OpenLayers.Class(OpenLayers.Protocol,{url:null,headers:null,params:null,callback:null,scope:null,readWithPOST:!1,updateWithPOST:!1,deleteWithPOST:!1,wildcarded:!1,srsInBBOX:!1,initialize:function(a){a=a||{};this.params={};this.headers={};OpenLayers.Protocol.prototype.initialize.apply(this,arguments);if(!this.filterToParams&&OpenLayers.Format.QueryStringFilter){var b=new OpenLayers.Format.QueryStringFilter({wildcarded:this.wildcarded,srsInBBOX:this.srsInBBOX});this.filterToParams=
2850 function(a,d){return b.write(a,d)}}},destroy:function(){this.headers=this.params=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){OpenLayers.Protocol.prototype.read.apply(this,arguments);a=a||{};a.params=OpenLayers.Util.applyDefaults(a.params,this.options.params);a=OpenLayers.Util.applyDefaults(a,this.options);a.filter&&this.filterToParams&&(a.params=this.filterToParams(a.filter,a.params));var b=void 0!==a.readWithPOST?a.readWithPOST:this.readWithPOST,c=new OpenLayers.Protocol.Response({requestType:"read"});
2851 b?(b=a.headers||{},b["Content-Type"]="application/x-www-form-urlencoded",c.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,c,a),data:OpenLayers.Util.getParameterString(a.params),headers:b})):c.priv=OpenLayers.Request.GET({url:a.url,callback:this.createCallback(this.handleRead,c,a),params:a.params,headers:a.headers});return c},handleRead:function(a,b){this.handleResponse(a,b)},create:function(a,b){var b=OpenLayers.Util.applyDefaults(b,this.options),c=new OpenLayers.Protocol.Response({reqFeatures:a,
2852 requestType:"create"});c.priv=OpenLayers.Request.POST({url:b.url,callback:this.createCallback(this.handleCreate,c,b),headers:b.headers,data:this.format.write(a)});return c},handleCreate:function(a,b){this.handleResponse(a,b)},update:function(a,b){var b=b||{},c=b.url||a.url||this.options.url+"/"+a.fid,b=OpenLayers.Util.applyDefaults(b,this.options),d=new OpenLayers.Protocol.Response({reqFeatures:a,requestType:"update"});d.priv=OpenLayers.Request[this.updateWithPOST?"POST":"PUT"]({url:c,callback:this.createCallback(this.handleUpdate,
2853 d,b),headers:b.headers,data:this.format.write(a)});return d},handleUpdate:function(a,b){this.handleResponse(a,b)},"delete":function(a,b){var b=b||{},c=b.url||a.url||this.options.url+"/"+a.fid,b=OpenLayers.Util.applyDefaults(b,this.options),d=new OpenLayers.Protocol.Response({reqFeatures:a,requestType:"delete"}),e=this.deleteWithPOST?"POST":"DELETE",c={url:c,callback:this.createCallback(this.handleDelete,d,b),headers:b.headers};this.deleteWithPOST&&(c.data=this.format.write(a));d.priv=OpenLayers.Request[e](c);
2854 return d},handleDelete:function(a,b){this.handleResponse(a,b)},handleResponse:function(a,b){var c=a.priv;b.callback&&(200<=c.status&&300>c.status?("delete"!=a.requestType&&(a.features=this.parseFeatures(c)),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE,b.callback.call(b.scope,a))},parseFeatures:function(a){var b=a.responseXML;if(!b||!b.documentElement)b=a.responseText;return!b||0>=b.length?null:this.format.read(b)},commit:function(a,b){function c(a){for(var b=
2855 a.features?a.features.length:0,c=Array(b),e=0;e<b;++e)c[e]=a.features[e].fid;o.insertIds=c;d.apply(this,[a])}function d(a){this.callUserCallback(a,b);n=n&&a.success();f++;f>=m&&b.callback&&(o.code=n?OpenLayers.Protocol.Response.SUCCESS:OpenLayers.Protocol.Response.FAILURE,b.callback.apply(b.scope,[o]))}var b=OpenLayers.Util.applyDefaults(b,this.options),e=[],f=0,g={};g[OpenLayers.State.INSERT]=[];g[OpenLayers.State.UPDATE]=[];g[OpenLayers.State.DELETE]=[];for(var h,i,j=[],k=0,l=a.length;k<l;++k)if(h=
2856 a[k],i=g[h.state])i.push(h),j.push(h);var m=(0<g[OpenLayers.State.INSERT].length?1:0)+g[OpenLayers.State.UPDATE].length+g[OpenLayers.State.DELETE].length,n=!0,o=new OpenLayers.Protocol.Response({reqFeatures:j});h=g[OpenLayers.State.INSERT];0<h.length&&e.push(this.create(h,OpenLayers.Util.applyDefaults({callback:c,scope:this},b.create)));h=g[OpenLayers.State.UPDATE];for(k=h.length-1;0<=k;--k)e.push(this.update(h[k],OpenLayers.Util.applyDefaults({callback:d,scope:this},b.update)));h=g[OpenLayers.State.DELETE];
2857 for(k=h.length-1;0<=k;--k)e.push(this["delete"](h[k],OpenLayers.Util.applyDefaults({callback:d,scope:this},b["delete"])));return e},abort:function(a){a&&a.priv.abort()},callUserCallback:function(a,b){var c=b[a.requestType];c&&c.callback&&c.callback.call(c.scope,a)},CLASS_NAME:"OpenLayers.Protocol.HTTP"});OpenLayers.Strategy.Cluster=OpenLayers.Class(OpenLayers.Strategy,{distance:20,threshold:null,features:null,clusters:null,clustering:!1,resolution:null,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a)this.layer.events.on({beforefeaturesadded:this.cacheFeatures,moveend:this.cluster,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.clearCache(),this.layer.events.un({beforefeaturesadded:this.cacheFeatures,moveend:this.cluster,
2858 scope:this}));return a},cacheFeatures:function(a){var b=!0;this.clustering||(this.clearCache(),this.features=a.features,this.cluster(),b=!1);return b},clearCache:function(){this.features=null},cluster:function(a){if((!a||a.zoomChanged)&&this.features)if(a=this.layer.map.getResolution(),a!=this.resolution||!this.clustersExist()){this.resolution=a;for(var a=[],b,c,d,e=0;e<this.features.length;++e)if(b=this.features[e],b.geometry){c=!1;for(var f=a.length-1;0<=f;--f)if(d=a[f],this.shouldCluster(d,b)){this.addToCluster(d,
2859 b);c=!0;break}c||a.push(this.createCluster(this.features[e]))}this.layer.removeAllFeatures();if(0<a.length){if(1<this.threshold){b=a.slice();a=[];e=0;for(d=b.length;e<d;++e)c=b[e],c.attributes.count<this.threshold?Array.prototype.push.apply(a,c.cluster):a.push(c)}this.clustering=!0;this.layer.addFeatures(a);this.clustering=!1}this.clusters=a}},clustersExist:function(){var a=!1;if(this.clusters&&0<this.clusters.length&&this.clusters.length==this.layer.features.length)for(var a=!0,b=0;b<this.clusters.length;++b)if(this.clusters[b]!=
2860 this.layer.features[b]){a=!1;break}return a},shouldCluster:function(a,b){var c=a.geometry.getBounds().getCenterLonLat(),d=b.geometry.getBounds().getCenterLonLat();return Math.sqrt(Math.pow(c.lon-d.lon,2)+Math.pow(c.lat-d.lat,2))/this.resolution<=this.distance},addToCluster:function(a,b){a.cluster.push(b);a.attributes.count+=1},createCluster:function(a){var b=a.geometry.getBounds().getCenterLonLat(),b=new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(b.lon,b.lat),{count:1});b.cluster=[a];
2861 return b},CLASS_NAME:"OpenLayers.Strategy.Cluster"});OpenLayers.Strategy.Filter=OpenLayers.Class(OpenLayers.Strategy,{filter:null,cache:null,caching:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.apply(this,arguments);a&&(this.cache=[],this.layer.events.on({beforefeaturesadded:this.handleAdd,beforefeaturesremoved:this.handleRemove,scope:this}));return a},deactivate:function(){this.cache=null;this.layer&&this.layer.events&&this.layer.events.un({beforefeaturesadded:this.handleAdd,beforefeaturesremoved:this.handleRemove,scope:this});
2862 return OpenLayers.Strategy.prototype.deactivate.apply(this,arguments)},handleAdd:function(a){if(!this.caching&&this.filter){var b=a.features;a.features=[];for(var c,d=0,e=b.length;d<e;++d)c=b[d],this.filter.evaluate(c)?a.features.push(c):this.cache.push(c)}},handleRemove:function(){this.caching||(this.cache=[])},setFilter:function(a){this.filter=a;a=this.cache;this.cache=[];this.handleAdd({features:this.layer.features});0<this.cache.length&&(this.caching=!0,this.layer.removeFeatures(this.cache.slice()),
2863 this.caching=!1);0<a.length&&(a={features:a},this.handleAdd(a),0<a.features.length&&(this.caching=!0,this.layer.addFeatures(a.features),this.caching=!1))},CLASS_NAME:"OpenLayers.Strategy.Filter"});OpenLayers.Protocol.SOS=function(a){var a=OpenLayers.Util.applyDefaults(a,OpenLayers.Protocol.SOS.DEFAULTS),b=OpenLayers.Protocol.SOS["v"+a.version.replace(/\./g,"_")];if(!b)throw"Unsupported SOS version: "+a.version;return new b(a)};OpenLayers.Protocol.SOS.DEFAULTS={version:"1.0.0"};OpenLayers.Format.WFSDescribeFeatureType=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{xsd:"http://www.w3.org/2001/XMLSchema"},readers:{xsd:{schema:function(a,b){var c=[],d={};this.readChildNodes(a,{complexTypes:c,customTypes:d});for(var e=a.attributes,f,g,h=0,i=e.length;h<i;++h)f=e[h],g=f.name,0==g.indexOf("xmlns")?this.setNamespace(g.split(":")[1]||"",f.value):b[g]=f.value;b.featureTypes=c;b.targetPrefix=this.namespaceAlias[b.targetNamespace];h=0;for(i=c.length;h<i;++h)e=c[h],f=d[e.typeName],
2864 d[e.typeName]&&(e.typeName=f.name)},complexType:function(a,b){var c={typeName:a.getAttribute("name")};this.readChildNodes(a,c);b.complexTypes.push(c)},complexContent:function(a,b){this.readChildNodes(a,b)},extension:function(a,b){this.readChildNodes(a,b)},sequence:function(a,b){var c={elements:[]};this.readChildNodes(a,c);b.properties=c.elements},element:function(a,b){if(b.elements){for(var c={},d=a.attributes,e,f=0,g=d.length;f<g;++f)e=d[f],c[e.name]=e.value;d=c.type;d||(d={},this.readChildNodes(a,
2865 d),c.restriction=d,c.type=d.base);c.localType=(d.base||d).split(":").pop();b.elements.push(c)}b.complexTypes&&(d=a.getAttribute("type"),c=d.split(":").pop(),b.customTypes[c]={name:a.getAttribute("name"),type:d})},simpleType:function(a,b){this.readChildNodes(a,b)},restriction:function(a,b){b.base=a.getAttribute("base");this.readRestriction(a,b)}}},readRestriction:function(a,b){for(var c=a.childNodes,d,e,f=0,g=c.length;f<g;++f)d=c[f],1==d.nodeType&&(e=d.nodeName.split(":").pop(),d=d.getAttribute("value"),
2866 b[e]?("string"==typeof b[e]&&(b[e]=[b[e]]),b[e].push(d)):b[e]=d)},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);return b},CLASS_NAME:"OpenLayers.Format.WFSDescribeFeatureType"});OpenLayers.Format.GeoRSS=OpenLayers.Class(OpenLayers.Format.XML,{rssns:"http://backend.userland.com/rss2",featureNS:"http://mapserver.gis.umn.edu/mapserver",georssns:"http://www.georss.org/georss",geons:"http://www.w3.org/2003/01/geo/wgs84_pos#",featureTitle:"Untitled",featureDescription:"No Description",gmlParser:null,xy:!1,createGeometryFromItem:function(a){var b=this.getElementsByTagNameNS(a,this.georssns,"point"),c=this.getElementsByTagNameNS(a,this.geons,"lat"),d=this.getElementsByTagNameNS(a,
2867 this.geons,"long"),e=this.getElementsByTagNameNS(a,this.georssns,"line"),f=this.getElementsByTagNameNS(a,this.georssns,"polygon"),g=this.getElementsByTagNameNS(a,this.georssns,"where"),a=this.getElementsByTagNameNS(a,this.georssns,"box");if(0<b.length||0<c.length&&0<d.length){0<b.length?(c=OpenLayers.String.trim(b[0].firstChild.nodeValue).split(/\s+/),2!=c.length&&(c=OpenLayers.String.trim(b[0].firstChild.nodeValue).split(/\s*,\s*/))):c=[parseFloat(c[0].firstChild.nodeValue),parseFloat(d[0].firstChild.nodeValue)];
2868 var h=new OpenLayers.Geometry.Point(c[1],c[0])}else if(0<e.length){c=OpenLayers.String.trim(this.getChildValue(e[0])).split(/\s+/);d=[];e=0;for(f=c.length;e<f;e+=2)b=new OpenLayers.Geometry.Point(c[e+1],c[e]),d.push(b);h=new OpenLayers.Geometry.LineString(d)}else if(0<f.length){c=OpenLayers.String.trim(this.getChildValue(f[0])).split(/\s+/);d=[];e=0;for(f=c.length;e<f;e+=2)b=new OpenLayers.Geometry.Point(c[e+1],c[e]),d.push(b);h=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)])}else 0<
2869 g.length?(this.gmlParser||(this.gmlParser=new OpenLayers.Format.GML({xy:this.xy})),h=this.gmlParser.parseFeature(g[0]).geometry):0<a.length&&(c=OpenLayers.String.trim(a[0].firstChild.nodeValue).split(/\s+/),d=[],3<c.length&&(b=new OpenLayers.Geometry.Point(c[1],c[0]),d.push(b),b=new OpenLayers.Geometry.Point(c[1],c[2]),d.push(b),b=new OpenLayers.Geometry.Point(c[3],c[2]),d.push(b),b=new OpenLayers.Geometry.Point(c[3],c[0]),d.push(b),b=new OpenLayers.Geometry.Point(c[1],c[0]),d.push(b)),h=new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(d)]));
2870 h&&(this.internalProjection&&this.externalProjection)&&h.transform(this.externalProjection,this.internalProjection);return h},createFeatureFromItem:function(a){var b=this.createGeometryFromItem(a),c=this._getChildValue(a,"*","title",this.featureTitle),d=this._getChildValue(a,"*","description",this._getChildValue(a,"*","content",this._getChildValue(a,"*","summary",this.featureDescription))),e=this._getChildValue(a,"*","link");if(!e)try{e=this.getElementsByTagNameNS(a,"*","link")[0].getAttribute("href")}catch(f){e=
2871 null}a=this._getChildValue(a,"*","id",null);b=new OpenLayers.Feature.Vector(b,{title:c,description:d,link:e});b.fid=a;return b},_getChildValue:function(a,b,c,d){return(a=this.getElementsByTagNameNS(a,b,c))&&a[0]&&a[0].firstChild&&a[0].firstChild.nodeValue?this.getChildValue(a[0]):void 0==d?"":d},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=null,b=this.getElementsByTagNameNS(a,"*","item");0==b.length&&(b=this.getElementsByTagNameNS(a,"*","entry"));
2872 for(var a=b.length,c=Array(a),d=0;d<a;d++)c[d]=this.createFeatureFromItem(b[d]);return c},write:function(a){var b;if(OpenLayers.Util.isArray(a)){b=this.createElementNS(this.rssns,"rss");for(var c=0,d=a.length;c<d;c++)b.appendChild(this.createFeatureXML(a[c]))}else b=this.createFeatureXML(a);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.rssns,"item"),d=this.createElementNS(this.rssns,"title");
2873 d.appendChild(this.createTextNode(a.attributes.title?a.attributes.title:""));var e=this.createElementNS(this.rssns,"description");e.appendChild(this.createTextNode(a.attributes.description?a.attributes.description:""));c.appendChild(d);c.appendChild(e);a.attributes.link&&(d=this.createElementNS(this.rssns,"link"),d.appendChild(this.createTextNode(a.attributes.link)),c.appendChild(d));for(var f in a.attributes)"link"==f||("title"==f||"description"==f)||(d=this.createTextNode(a.attributes[f]),e=f,-1!=
2874 f.search(":")&&(e=f.split(":")[1]),e=this.createElementNS(this.featureNS,"feature:"+e),e.appendChild(d),c.appendChild(e));c.appendChild(b);return c},buildGeometryNode:function(a){this.internalProjection&&this.externalProjection&&(a=a.clone(),a.transform(this.internalProjection,this.externalProjection));var b;if("OpenLayers.Geometry.Polygon"==a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:polygon"),b.appendChild(this.buildCoordinatesNode(a.components[0]));else if("OpenLayers.Geometry.LineString"==
2875 a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:line"),b.appendChild(this.buildCoordinatesNode(a));else if("OpenLayers.Geometry.Point"==a.CLASS_NAME)b=this.createElementNS(this.georssns,"georss:point"),b.appendChild(this.buildCoordinatesNode(a));else throw"Couldn't parse "+a.CLASS_NAME;return b},buildCoordinatesNode:function(a){var b=null;a.components&&(b=a.components);if(b){for(var a=b.length,c=Array(a),d=0;d<a;d++)c[d]=b[d].y+" "+b[d].x;b=c.join(" ")}else b=a.y+" "+a.x;return this.createTextNode(b)},
2876 CLASS_NAME:"OpenLayers.Format.GeoRSS"});OpenLayers.Format.WPSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.0.0",CLASS_NAME:"OpenLayers.Format.WPSCapabilities"});OpenLayers.Format.WPSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows/1.1",wps:"http://www.opengis.net/wps/1.0.0",xlink:"http://www.w3.org/1999/xlink"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a])},read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);
2877 var b={};this.readNode(a,b);return b},readers:{wps:{Capabilities:function(a,b){this.readChildNodes(a,b)},ProcessOfferings:function(a,b){b.processOfferings={};this.readChildNodes(a,b.processOfferings)},Process:function(a,b){var c={processVersion:this.getAttributeNS(a,this.namespaces.wps,"processVersion")};this.readChildNodes(a,c);b[c.identifier]=c},Languages:function(a,b){b.languages=[];this.readChildNodes(a,b.languages)},Default:function(a,b){var c={isDefault:!0};this.readChildNodes(a,c);b.push(c)},
2878 Supported:function(a,b){var c={};this.readChildNodes(a,c);b.push(c)}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WPSCapabilities.v1_0_0"});OpenLayers.Control.PinchZoom=OpenLayers.Class(OpenLayers.Control,{type:OpenLayers.Control.TYPE_TOOL,containerCenter:null,pinchOrigin:null,currentCenter:null,autoActivate:!0,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.handler=new OpenLayers.Handler.Pinch(this,{start:this.pinchStart,move:this.pinchMove,done:this.pinchDone},this.handlerOptions)},activate:function(){var a=OpenLayers.Control.prototype.activate.apply(this,arguments);a&&(this.map.events.on({moveend:this.updateContainerCenter,
2879 scope:this}),this.updateContainerCenter());return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.apply(this,arguments);this.map&&this.map.events&&this.map.events.un({moveend:this.updateContainerCenter,scope:this});return a},updateContainerCenter:function(){var a=this.map.layerContainerDiv;this.containerCenter={x:parseInt(a.style.left,10)+50,y:parseInt(a.style.top,10)+50}},pinchStart:function(a){this.currentCenter=this.pinchOrigin=a.xy},pinchMove:function(a,b){var c=b.scale,
2880 d=this.containerCenter,e=this.pinchOrigin,f=a.xy,g=Math.round(f.x-e.x+(c-1)*(d.x-e.x)),d=Math.round(f.y-e.y+(c-1)*(d.y-e.y));this.applyTransform("translate("+g+"px, "+d+"px) scale("+c+")");this.currentCenter=f},applyTransform:function(a){var b=this.map.layerContainerDiv.style;b["-webkit-transform"]=a;b["-moz-transform"]=a},pinchDone:function(a,b,c){this.applyTransform("");a=this.map.getZoomForResolution(this.map.getResolution()/c.scale,!0);if(a!==this.map.getZoom()||!this.currentCenter.equals(this.pinchOrigin)){var b=
2881 this.map.getResolutionForZoom(a),c=this.map.getLonLatFromPixel(this.pinchOrigin),d=this.currentCenter,e=this.map.getSize();c.lon+=b*(e.w/2-d.x);c.lat-=b*(e.h/2-d.y);this.map.div.clientWidth=this.map.div.clientWidth;this.map.setCenter(c,a)}},CLASS_NAME:"OpenLayers.Control.PinchZoom"});OpenLayers.Control.TouchNavigation=OpenLayers.Class(OpenLayers.Control,{dragPan:null,dragPanOptions:null,pinchZoom:null,pinchZoomOptions:null,clickHandlerOptions:null,documentDrag:!1,autoActivate:!0,initialize:function(a){this.handlers={};OpenLayers.Control.prototype.initialize.apply(this,arguments)},destroy:function(){this.deactivate();this.dragPan&&this.dragPan.destroy();this.dragPan=null;this.pinchZoom&&(this.pinchZoom.destroy(),delete this.pinchZoom);OpenLayers.Control.prototype.destroy.apply(this,
2882 arguments)},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.dragPan.activate(),this.handlers.click.activate(),this.pinchZoom.activate(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,arguments)?(this.dragPan.deactivate(),this.handlers.click.deactivate(),this.pinchZoom.deactivate(),!0):!1},draw:function(){var a={click:this.defaultClick,dblclick:this.defaultDblClick},b=OpenLayers.Util.extend({"double":!0,stopDouble:!0,
2883 pixelTolerance:2},this.clickHandlerOptions);this.handlers.click=new OpenLayers.Handler.Click(this,a,b);this.dragPan=new OpenLayers.Control.DragPan(OpenLayers.Util.extend({map:this.map,documentDrag:this.documentDrag},this.dragPanOptions));this.dragPan.draw();this.pinchZoom=new OpenLayers.Control.PinchZoom(OpenLayers.Util.extend({map:this.map},this.pinchZoomOptions))},defaultClick:function(a){a.lastTouches&&2==a.lastTouches.length&&this.map.zoomOut()},defaultDblClick:function(a){this.map.setCenter(this.map.getLonLatFromViewPortPx(a.xy),
2884 this.map.zoom+1)},CLASS_NAME:"OpenLayers.Control.TouchNavigation"});OpenLayers.Style2=OpenLayers.Class({id:null,name:null,title:null,description:null,layerName:null,isDefault:!1,rules:null,initialize:function(a){OpenLayers.Util.extend(this,a);this.id=OpenLayers.Util.createUniqueID(this.CLASS_NAME+"_")},destroy:function(){for(var a=0,b=this.rules.length;a<b;a++)this.rules[a].destroy();delete this.rules},clone:function(){var a=OpenLayers.Util.extend({},this);if(this.rules){a.rules=[];for(var b=0,c=this.rules.length;b<c;++b)a.rules.push(this.rules[b].clone())}return new OpenLayers.Style2(a)},
2885 CLASS_NAME:"OpenLayers.Style2"});OpenLayers.Format.WFS=OpenLayers.Class(OpenLayers.Format.GML,{layer:null,wfsns:"http://www.opengis.net/wfs",ogcns:"http://www.opengis.net/ogc",initialize:function(a,b){OpenLayers.Format.GML.prototype.initialize.apply(this,[a]);this.layer=b;this.layer.featureNS&&(this.featureNS=this.layer.featureNS);this.layer.options.geometry_column&&(this.geometryName=this.layer.options.geometry_column);this.layer.options.typename&&(this.featureName=this.layer.options.typename)},write:function(a){var b=this.createElementNS(this.wfsns,
2886 "wfs:Transaction");b.setAttribute("version","1.0.0");b.setAttribute("service","WFS");for(var c=0;c<a.length;c++)switch(a[c].state){case OpenLayers.State.INSERT:b.appendChild(this.insert(a[c]));break;case OpenLayers.State.UPDATE:b.appendChild(this.update(a[c]));break;case OpenLayers.State.DELETE:b.appendChild(this.remove(a[c]))}return OpenLayers.Format.XML.prototype.write.apply(this,[b])},createFeatureXML:function(a){var b=this.buildGeometryNode(a.geometry),c=this.createElementNS(this.featureNS,"feature:"+
2887 this.geometryName);c.appendChild(b);b=this.createElementNS(this.featureNS,"feature:"+this.featureName);b.appendChild(c);for(var d in a.attributes){var c=this.createTextNode(a.attributes[d]),e=d;-1!=d.search(":")&&(e=d.split(":")[1]);e=this.createElementNS(this.featureNS,"feature:"+e);e.appendChild(c);b.appendChild(e)}return b},insert:function(a){var b=this.createElementNS(this.wfsns,"wfs:Insert");b.appendChild(this.createFeatureXML(a));return b},update:function(a){a.fid||OpenLayers.Console.userError(OpenLayers.i18n("noFID"));
2888 var b=this.createElementNS(this.wfsns,"wfs:Update");b.setAttribute("typeName",this.featurePrefix+":"+this.featureName);b.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var c=this.createElementNS(this.wfsns,"wfs:Property"),d=this.createElementNS(this.wfsns,"wfs:Name"),e=this.createTextNode(this.geometryName);d.appendChild(e);c.appendChild(d);d=this.createElementNS(this.wfsns,"wfs:Value");e=this.buildGeometryNode(a.geometry);a.layer&&e.setAttribute("srsName",a.layer.projection.getCode());
2889 d.appendChild(e);c.appendChild(d);b.appendChild(c);for(var f in a.attributes)c=this.createElementNS(this.wfsns,"wfs:Property"),d=this.createElementNS(this.wfsns,"wfs:Name"),d.appendChild(this.createTextNode(f)),c.appendChild(d),d=this.createElementNS(this.wfsns,"wfs:Value"),d.appendChild(this.createTextNode(a.attributes[f])),c.appendChild(d),b.appendChild(c);c=this.createElementNS(this.ogcns,"ogc:Filter");f=this.createElementNS(this.ogcns,"ogc:FeatureId");f.setAttribute("fid",a.fid);c.appendChild(f);
2890 b.appendChild(c);return b},remove:function(a){if(!a.fid)return OpenLayers.Console.userError(OpenLayers.i18n("noFID")),!1;var b=this.createElementNS(this.wfsns,"wfs:Delete");b.setAttribute("typeName",this.featurePrefix+":"+this.featureName);b.setAttribute("xmlns:"+this.featurePrefix,this.featureNS);var c=this.createElementNS(this.ogcns,"ogc:Filter"),d=this.createElementNS(this.ogcns,"ogc:FeatureId");d.setAttribute("fid",a.fid);c.appendChild(d);b.appendChild(c);return b},destroy:function(){this.layer=
2891 null},CLASS_NAME:"OpenLayers.Format.WFS"});OpenLayers.Format.SLD.v1_0_0_GeoServer=OpenLayers.Class(OpenLayers.Format.SLD.v1_0_0,{version:"1.0.0",profile:"GeoServer",readers:OpenLayers.Util.applyDefaults({sld:OpenLayers.Util.applyDefaults({Priority:function(a,b){var c=this.readers.ogc._expression.call(this,a);c&&(b.priority=c)},VendorOption:function(a,b){b.vendorOptions||(b.vendorOptions={});b.vendorOptions[a.getAttribute("name")]=this.getChildValue(a)}},OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld)},OpenLayers.Format.SLD.v1_0_0.prototype.readers),
2892 writers:OpenLayers.Util.applyDefaults({sld:OpenLayers.Util.applyDefaults({Priority:function(a){return this.writers.sld._OGCExpression.call(this,"sld:Priority",a)},VendorOption:function(a){return this.createElementNSPlus("sld:VendorOption",{attributes:{name:a.name},value:a.value})},TextSymbolizer:function(a){var b=OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.TextSymbolizer.apply(this,arguments);!1!==a.graphic&&(a.externalGraphic||a.graphicName)&&this.writeNode("Graphic",a,b);"priority"in a&&
2893 this.writeNode("Priority",a.priority,b);return this.addVendorOptions(b,a)},PointSymbolizer:function(a){return this.addVendorOptions(OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.PointSymbolizer.apply(this,arguments),a)},LineSymbolizer:function(a){return this.addVendorOptions(OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.LineSymbolizer.apply(this,arguments),a)},PolygonSymbolizer:function(a){return this.addVendorOptions(OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld.PolygonSymbolizer.apply(this,
2894 arguments),a)}},OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld)},OpenLayers.Format.SLD.v1_0_0.prototype.writers),addVendorOptions:function(a,b){if(b.vendorOptions)for(var c in b.vendorOptions)this.writeNode("VendorOption",{name:c,value:b.vendorOptions[c]},a);return a},CLASS_NAME:"OpenLayers.Format.SLD.v1_0_0_GeoServer"});OpenLayers.Layer.Boxes=OpenLayers.Class(OpenLayers.Layer.Markers,{drawMarker:function(a){var b=this.map.getLayerPxFromLonLat({lon:a.bounds.left,lat:a.bounds.top}),c=this.map.getLayerPxFromLonLat({lon:a.bounds.right,lat:a.bounds.bottom});null==c||null==b?a.display(!1):(b=a.draw(b,{w:Math.max(1,c.x-b.x),h:Math.max(1,c.y-b.y)}),a.drawn||(this.div.appendChild(b),a.drawn=!0))},removeMarker:function(a){OpenLayers.Util.removeItem(this.markers,a);null!=a.div&&a.div.parentNode==this.div&&this.div.removeChild(a.div)},
2895 CLASS_NAME:"OpenLayers.Layer.Boxes"});OpenLayers.Format.WFSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.WFSCapabilities.v1,{readers:{wfs:OpenLayers.Util.applyDefaults({Service:function(a,b){b.service={};this.readChildNodes(a,b.service)},Fees:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.fees=c)},AccessConstraints:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.accessConstraints=c)},OnlineResource:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.onlineResource=
2896 c)},Keywords:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.keywords=c.split(", "))},Capability:function(a,b){b.capability={};this.readChildNodes(a,b.capability)},Request:function(a,b){b.request={};this.readChildNodes(a,b.request)},GetFeature:function(a,b){b.getfeature={href:{},formats:[]};this.readChildNodes(a,b.getfeature)},ResultFormat:function(a,b){for(var c=a.childNodes,d,e=0;e<c.length;e++)d=c[e],1==d.nodeType&&b.formats.push(d.nodeName)},DCPType:function(a,b){this.readChildNodes(a,
2897 b)},HTTP:function(a,b){this.readChildNodes(a,b.href)},Get:function(a,b){b.get=a.getAttribute("onlineResource")},Post:function(a,b){b.post=a.getAttribute("onlineResource")},SRS:function(a,b){var c=this.getChildValue(a);c&&(b.srs=c)}},OpenLayers.Format.WFSCapabilities.v1.prototype.readers.wfs)},CLASS_NAME:"OpenLayers.Format.WFSCapabilities.v1_0_0"});OpenLayers.Format.WMSCapabilities=OpenLayers.Class(OpenLayers.Format.XML.VersionedOGC,{defaultVersion:"1.1.1",profile:null,CLASS_NAME:"OpenLayers.Format.WMSCapabilities"});OpenLayers.Format.WMSCapabilities.v1=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{wms:"http://www.opengis.net/wms",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},defaultPrefix:"wms",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=a;a&&9==a.nodeType&&(a=a.documentElement);var c={};this.readNode(a,c);void 0===c.service&&(a=new OpenLayers.Format.OGCExceptionReport,c.error=a.read(b));return c},readers:{wms:{Service:function(a,
2898 b){b.service={};this.readChildNodes(a,b.service)},Name:function(a,b){b.name=this.getChildValue(a)},Title:function(a,b){b.title=this.getChildValue(a)},Abstract:function(a,b){b["abstract"]=this.getChildValue(a)},BoundingBox:function(a){var b={};b.bbox=[parseFloat(a.getAttribute("minx")),parseFloat(a.getAttribute("miny")),parseFloat(a.getAttribute("maxx")),parseFloat(a.getAttribute("maxy"))];a={x:parseFloat(a.getAttribute("resx")),y:parseFloat(a.getAttribute("resy"))};if(!isNaN(a.x)||!isNaN(a.y))b.res=
2899 a;return b},OnlineResource:function(a,b){b.href=this.getAttributeNS(a,this.namespaces.xlink,"href")},ContactInformation:function(a,b){b.contactInformation={};this.readChildNodes(a,b.contactInformation)},ContactPersonPrimary:function(a,b){b.personPrimary={};this.readChildNodes(a,b.personPrimary)},ContactPerson:function(a,b){b.person=this.getChildValue(a)},ContactOrganization:function(a,b){b.organization=this.getChildValue(a)},ContactPosition:function(a,b){b.position=this.getChildValue(a)},ContactAddress:function(a,
2900 b){b.contactAddress={};this.readChildNodes(a,b.contactAddress)},AddressType:function(a,b){b.type=this.getChildValue(a)},Address:function(a,b){b.address=this.getChildValue(a)},City:function(a,b){b.city=this.getChildValue(a)},StateOrProvince:function(a,b){b.stateOrProvince=this.getChildValue(a)},PostCode:function(a,b){b.postcode=this.getChildValue(a)},Country:function(a,b){b.country=this.getChildValue(a)},ContactVoiceTelephone:function(a,b){b.phone=this.getChildValue(a)},ContactFacsimileTelephone:function(a,
2901 b){b.fax=this.getChildValue(a)},ContactElectronicMailAddress:function(a,b){b.email=this.getChildValue(a)},Fees:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.fees=c)},AccessConstraints:function(a,b){var c=this.getChildValue(a);c&&"none"!=c.toLowerCase()&&(b.accessConstraints=c)},Capability:function(a,b){b.capability={nestedLayers:[],layers:[]};this.readChildNodes(a,b.capability)},Request:function(a,b){b.request={};this.readChildNodes(a,b.request)},GetCapabilities:function(a,
2902 b){b.getcapabilities={formats:[]};this.readChildNodes(a,b.getcapabilities)},Format:function(a,b){OpenLayers.Util.isArray(b.formats)?b.formats.push(this.getChildValue(a)):b.format=this.getChildValue(a)},DCPType:function(a,b){this.readChildNodes(a,b)},HTTP:function(a,b){this.readChildNodes(a,b)},Get:function(a,b){b.get={};this.readChildNodes(a,b.get);b.href||(b.href=b.get.href)},Post:function(a,b){b.post={};this.readChildNodes(a,b.post);b.href||(b.href=b.get.href)},GetMap:function(a,b){b.getmap={formats:[]};
2903 this.readChildNodes(a,b.getmap)},GetFeatureInfo:function(a,b){b.getfeatureinfo={formats:[]};this.readChildNodes(a,b.getfeatureinfo)},Exception:function(a,b){b.exception={formats:[]};this.readChildNodes(a,b.exception)},Layer:function(a,b){var c,d;b.capability?(d=b.capability,c=b):d=b;var e=a.getAttributeNode("queryable"),f=e&&e.specified?a.getAttribute("queryable"):null,g=(e=a.getAttributeNode("cascaded"))&&e.specified?a.getAttribute("cascaded"):null,e=(e=a.getAttributeNode("opaque"))&&e.specified?
2904 a.getAttribute("opaque"):null,h=a.getAttribute("noSubsets"),i=a.getAttribute("fixedWidth"),j=a.getAttribute("fixedHeight"),k=c||{},l=OpenLayers.Util.extend;c={nestedLayers:[],styles:c?[].concat(c.styles):[],srs:c?l({},k.srs):{},metadataURLs:[],bbox:c?l({},k.bbox):{},llbbox:k.llbbox,dimensions:c?l({},k.dimensions):{},authorityURLs:c?l({},k.authorityURLs):{},identifiers:{},keywords:[],queryable:f&&""!==f?"1"===f||"true"===f:k.queryable||!1,cascaded:null!==g?parseInt(g):k.cascaded||0,opaque:e?"1"===
2905 e||"true"===e:k.opaque||!1,noSubsets:null!==h?"1"===h||"true"===h:k.noSubsets||!1,fixedWidth:null!=i?parseInt(i):k.fixedWidth||0,fixedHeight:null!=j?parseInt(j):k.fixedHeight||0,minScale:k.minScale,maxScale:k.maxScale,attribution:k.attribution};b.nestedLayers.push(c);c.capability=d;this.readChildNodes(a,c);delete c.capability;if(c.name&&(f=c.name.split(":"),g=d.request,e=g.getfeatureinfo,0<f.length&&(c.prefix=f[0]),d.layers.push(c),void 0===c.formats&&(c.formats=g.getmap.formats),void 0===c.infoFormats&&
2906 e))c.infoFormats=e.formats},Attribution:function(a,b){b.attribution={};this.readChildNodes(a,b.attribution)},LogoURL:function(a,b){b.logo={width:a.getAttribute("width"),height:a.getAttribute("height")};this.readChildNodes(a,b.logo)},Style:function(a,b){var c={};b.styles.push(c);this.readChildNodes(a,c)},LegendURL:function(a,b){var c={width:a.getAttribute("width"),height:a.getAttribute("height")};b.legend=c;this.readChildNodes(a,c)},MetadataURL:function(a,b){var c={type:a.getAttribute("type")};b.metadataURLs.push(c);
2907 this.readChildNodes(a,c)},DataURL:function(a,b){b.dataURL={};this.readChildNodes(a,b.dataURL)},FeatureListURL:function(a,b){b.featureListURL={};this.readChildNodes(a,b.featureListURL)},AuthorityURL:function(a,b){var c=a.getAttribute("name"),d={};this.readChildNodes(a,d);b.authorityURLs[c]=d.href},Identifier:function(a,b){var c=a.getAttribute("authority");b.identifiers[c]=this.getChildValue(a)},KeywordList:function(a,b){this.readChildNodes(a,b)},SRS:function(a,b){b.srs[this.getChildValue(a)]=!0}}},
2908 CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1"});OpenLayers.Format.WMSCapabilities.v1_3=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{wms:OpenLayers.Util.applyDefaults({WMS_Capabilities:function(a,b){this.readChildNodes(a,b)},LayerLimit:function(a,b){b.layerLimit=parseInt(this.getChildValue(a))},MaxWidth:function(a,b){b.maxWidth=parseInt(this.getChildValue(a))},MaxHeight:function(a,b){b.maxHeight=parseInt(this.getChildValue(a))},BoundingBox:function(a,b){var c=OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms.BoundingBox.apply(this,
2909 [a,b]);c.srs=a.getAttribute("CRS");b.bbox[c.srs]=c},CRS:function(a,b){this.readers.wms.SRS.apply(this,[a,b])},EX_GeographicBoundingBox:function(a,b){b.llbbox=[];this.readChildNodes(a,b.llbbox)},westBoundLongitude:function(a,b){b[0]=this.getChildValue(a)},eastBoundLongitude:function(a,b){b[2]=this.getChildValue(a)},southBoundLatitude:function(a,b){b[1]=this.getChildValue(a)},northBoundLatitude:function(a,b){b[3]=this.getChildValue(a)},MinScaleDenominator:function(a,b){b.maxScale=parseFloat(this.getChildValue(a)).toPrecision(16)},
2910 MaxScaleDenominator:function(a,b){b.minScale=parseFloat(this.getChildValue(a)).toPrecision(16)},Dimension:function(a,b){var c={name:a.getAttribute("name").toLowerCase(),units:a.getAttribute("units"),unitsymbol:a.getAttribute("unitSymbol"),nearestVal:"1"===a.getAttribute("nearestValue"),multipleVal:"1"===a.getAttribute("multipleValues"),"default":a.getAttribute("default")||"",current:"1"===a.getAttribute("current"),values:this.getChildValue(a).split(",")};b.dimensions[c.name]=c},Keyword:function(a,
2911 b){var c={value:this.getChildValue(a),vocabulary:a.getAttribute("vocabulary")};b.keywords&&b.keywords.push(c)}},OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms),sld:{UserDefinedSymbolization:function(a,b){this.readers.wms.UserDefinedSymbolization.apply(this,[a,b]);b.userSymbols.inlineFeature=1==parseInt(a.getAttribute("InlineFeature"));b.userSymbols.remoteWCS=1==parseInt(a.getAttribute("RemoteWCS"))},DescribeLayer:function(a,b){this.readers.wms.DescribeLayer.apply(this,[a,b])},GetLegendGraphic:function(a,
2912 b){this.readers.wms.GetLegendGraphic.apply(this,[a,b])}}},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3"});OpenLayers.Layer.Zoomify=OpenLayers.Class(OpenLayers.Layer.Grid,{size:null,isBaseLayer:!0,standardTileSize:256,tileOriginCorner:"tl",numberOfTiers:0,tileCountUpToTier:null,tierSizeInTiles:null,tierImageSize:null,initialize:function(a,b,c,d){this.initializeZoomify(c);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a,b,c,{},d])},initializeZoomify:function(a){var a=a.clone(),b=new OpenLayers.Size(Math.ceil(a.w/this.standardTileSize),Math.ceil(a.h/this.standardTileSize));this.tierSizeInTiles=[b];
2913 for(this.tierImageSize=[a];a.w>this.standardTileSize||a.h>this.standardTileSize;)a=new OpenLayers.Size(Math.floor(a.w/2),Math.floor(a.h/2)),b=new OpenLayers.Size(Math.ceil(a.w/this.standardTileSize),Math.ceil(a.h/this.standardTileSize)),this.tierSizeInTiles.push(b),this.tierImageSize.push(a);this.tierSizeInTiles.reverse();this.tierImageSize.reverse();this.numberOfTiers=this.tierSizeInTiles.length;this.tileCountUpToTier=[0];for(a=1;a<this.numberOfTiers;a++)this.tileCountUpToTier.push(this.tierSizeInTiles[a-
2914 1].w*this.tierSizeInTiles[a-1].h+this.tileCountUpToTier[a-1])},destroy:function(){OpenLayers.Layer.Grid.prototype.destroy.apply(this,arguments);this.tileCountUpToTier.length=0;this.tierSizeInTiles.length=0;this.tierImageSize.length=0},clone:function(a){null==a&&(a=new OpenLayers.Layer.Zoomify(this.name,this.url,this.size,this.options));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var a=this.adjustBounds(a),b=this.map.getResolution(),c=Math.round((a.left-this.tileOrigin.lon)/
2915 (b*this.tileSize.w)),a=Math.round((this.tileOrigin.lat-a.top)/(b*this.tileSize.h)),b=this.map.getZoom(),c="TileGroup"+Math.floor((c+a*this.tierSizeInTiles[b].w+this.tileCountUpToTier[b])/256)+"/"+b+"-"+c+"-"+a+".jpg",a=this.url;OpenLayers.Util.isArray(a)&&(a=this.selectUrl(c,a));return a+c},getImageSize:function(){if(0<arguments.length){var a=this.adjustBounds(arguments[0]),b=this.map.getResolution(),c=Math.round((a.left-this.tileOrigin.lon)/(b*this.tileSize.w)),a=Math.round((this.tileOrigin.lat-
2916 a.top)/(b*this.tileSize.h)),b=this.map.getZoom(),d=this.standardTileSize,e=this.standardTileSize;c==this.tierSizeInTiles[b].w-1&&(d=this.tierImageSize[b].w%this.standardTileSize);a==this.tierSizeInTiles[b].h-1&&(e=this.tierImageSize[b].h%this.standardTileSize);return new OpenLayers.Size(d,e)}return this.tileSize},setMap:function(a){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.tileOrigin=new OpenLayers.LonLat(this.map.maxExtent.left,this.map.maxExtent.top)},calculateGridLayout:function(a,
2917 b,c){var d=c*this.tileSize.w,c=c*this.tileSize.h,e=a.left-b.lon,f=Math.floor(e/d)-this.buffer,a=b.lat-a.top+c,g=Math.floor(a/c)-this.buffer;return{tilelon:d,tilelat:c,tileoffsetlon:b.lon+f*d,tileoffsetlat:b.lat-c*g,tileoffsetx:-(e/d-f)*this.tileSize.w,tileoffsety:(g-a/c)*this.tileSize.h}},CLASS_NAME:"OpenLayers.Layer.Zoomify"});OpenLayers.Layer.MapServer=OpenLayers.Class(OpenLayers.Layer.Grid,{DEFAULT_PARAMS:{mode:"map",map_imagetype:"png"},initialize:function(a,b,c,d){OpenLayers.Layer.Grid.prototype.initialize.apply(this,arguments);this.params=OpenLayers.Util.applyDefaults(this.params,this.DEFAULT_PARAMS);if(null==d||null==d.isBaseLayer)this.isBaseLayer="true"!=this.params.transparent&&!0!=this.params.transparent},clone:function(a){null==a&&(a=new OpenLayers.Layer.MapServer(this.name,this.url,this.params,this.getOptions()));
2918 return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getURL:function(a){var a=this.adjustBounds(a),a=[a.left,a.bottom,a.right,a.top],b=this.getImageSize();return this.getFullRequestString({mapext:a,imgext:a,map_size:[b.w,b.h],imgx:b.w/2,imgy:b.h/2,imgxy:[b.w,b.h]})},getFullRequestString:function(a,b){var c=null==b?this.url:b,d=OpenLayers.Util.extend({},this.params),d=OpenLayers.Util.extend(d,a),e=OpenLayers.Util.getParameterString(d);OpenLayers.Util.isArray(c)&&(c=this.selectUrl(e,c));
2919 var e=OpenLayers.Util.upperCaseObject(OpenLayers.Util.getParameters(c)),f;for(f in d)f.toUpperCase()in e&&delete d[f];e=OpenLayers.Util.getParameterString(d);d=c;e=e.replace(/,/g,"+");""!=e&&(f=c.charAt(c.length-1),d="&"==f||"?"==f?d+e:-1==c.indexOf("?")?d+("?"+e):d+("&"+e));return d},CLASS_NAME:"OpenLayers.Layer.MapServer"});OpenLayers.Renderer.VML=OpenLayers.Class(OpenLayers.Renderer.Elements,{xmlns:"urn:schemas-microsoft-com:vml",symbolCache:{},offset:null,initialize:function(a){if(this.supported()){if(!document.namespaces.olv){document.namespaces.add("olv",this.xmlns);for(var b=document.createStyleSheet(),c="shape rect oval fill stroke imagedata group textbox".split(" "),d=0,e=c.length;d<e;d++)b.addRule("olv\\:"+c[d],"behavior: url(#default#VML); position: absolute; display: inline-block;")}OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
2920 arguments)}},supported:function(){return!!document.namespaces},setExtent:function(a,b){var c=OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,arguments),d=this.getResolution(),e=a.left/d|0,d=a.top/d-this.size.h|0;b||!this.offset?(this.offset={x:e,y:d},d=e=0):(e-=this.offset.x,d-=this.offset.y);this.root.coordorigin=e-this.xOffset+" "+d;for(var e=[this.root,this.vectorRoot,this.textRoot],f=0,g=e.length;f<g;++f)d=e[f],d.coordsize=this.size.w+" "+this.size.h;this.root.style.flip="y";return c},
2921 setSize:function(a){OpenLayers.Renderer.prototype.setSize.apply(this,arguments);for(var b=[this.rendererRoot,this.root,this.vectorRoot,this.textRoot],c=this.size.w+"px",d=this.size.h+"px",e,f=0,g=b.length;f<g;++f)e=b[f],e.style.width=c,e.style.height=d},getNodeType:function(a,b){var c=null;switch(a.CLASS_NAME){case "OpenLayers.Geometry.Point":c=b.externalGraphic?"olv:rect":this.isComplexSymbol(b.graphicName)?"olv:shape":"olv:oval";break;case "OpenLayers.Geometry.Rectangle":c="olv:rect";break;case "OpenLayers.Geometry.LineString":case "OpenLayers.Geometry.LinearRing":case "OpenLayers.Geometry.Polygon":case "OpenLayers.Geometry.Curve":c=
2922 "olv:shape"}return c},setStyle:function(a,b,c,d){var b=b||a._style,c=c||a._options,e=b.fillColor;if("OpenLayers.Geometry.Point"===a._geometryClass)if(b.externalGraphic){c.isFilled=!0;b.graphicTitle&&(a.title=b.graphicTitle);var e=b.graphicWidth||b.graphicHeight,f=b.graphicHeight||b.graphicWidth,e=e?e:2*b.pointRadius,f=f?f:2*b.pointRadius,g=this.getResolution(),h=void 0!=b.graphicXOffset?b.graphicXOffset:-(0.5*e),i=void 0!=b.graphicYOffset?b.graphicYOffset:-(0.5*f);a.style.left=((d.x-this.featureDx)/
2923 g-this.offset.x+h|0)+"px";a.style.top=(d.y/g-this.offset.y-(i+f)|0)+"px";a.style.width=e+"px";a.style.height=f+"px";a.style.flip="y";e="none";c.isStroked=!1}else this.isComplexSymbol(b.graphicName)?(f=this.importSymbol(b.graphicName),a.path=f.path,a.coordorigin=f.left+","+f.bottom,f=f.size,a.coordsize=f+","+f,this.drawCircle(a,d,b.pointRadius),a.style.flip="y"):this.drawCircle(a,d,b.pointRadius);c.isFilled?a.fillcolor=e:a.filled="false";d=a.getElementsByTagName("fill");d=0==d.length?null:d[0];if(c.isFilled){d||
2924 (d=this.createNode("olv:fill",a.id+"_fill"));d.opacity=b.fillOpacity;if("OpenLayers.Geometry.Point"===a._geometryClass&&b.externalGraphic&&(b.graphicOpacity&&(d.opacity=b.graphicOpacity),d.src=b.externalGraphic,d.type="frame",!b.graphicWidth||!b.graphicHeight))d.aspect="atmost";d.parentNode!=a&&a.appendChild(d)}else d&&a.removeChild(d);e=b.rotation;if(void 0!==e||void 0!==a._rotation)a._rotation=e,b.externalGraphic?(this.graphicRotate(a,h,i,b),d.opacity=0):"OpenLayers.Geometry.Point"===a._geometryClass&&
2925 (a.style.rotation=e||0);h=a.getElementsByTagName("stroke");h=0==h.length?null:h[0];if(c.isStroked){if(h||(h=this.createNode("olv:stroke",a.id+"_stroke"),a.appendChild(h)),h.on=!0,h.color=b.strokeColor,h.weight=b.strokeWidth+"px",h.opacity=b.strokeOpacity,h.endcap="butt"==b.strokeLinecap?"flat":b.strokeLinecap||"round",b.strokeDashstyle)h.dashstyle=this.dashStyle(b)}else a.stroked=!1,h&&(h.on=!1);"inherit"!=b.cursor&&null!=b.cursor&&(a.style.cursor=b.cursor);return a},graphicRotate:function(a,b,c,
2926 d){var d=d||a._style,e=d.rotation||0,f,g;if(!d.graphicWidth||!d.graphicHeight){var h=new Image;h.onreadystatechange=OpenLayers.Function.bind(function(){if("complete"==h.readyState||"interactive"==h.readyState)f=h.width/h.height,g=Math.max(2*d.pointRadius,d.graphicWidth||0,d.graphicHeight||0),b*=f,d.graphicWidth=g*f,d.graphicHeight=g,this.graphicRotate(a,b,c,d)},this);h.src=d.externalGraphic}else{g=Math.max(d.graphicWidth,d.graphicHeight);f=d.graphicWidth/d.graphicHeight;var i=Math.round(d.graphicWidth||
2927 g*f),j=Math.round(d.graphicHeight||g);a.style.width=i+"px";a.style.height=j+"px";var k=document.getElementById(a.id+"_image");k||(k=this.createNode("olv:imagedata",a.id+"_image"),a.appendChild(k));k.style.width=i+"px";k.style.height=j+"px";k.src=d.externalGraphic;k.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='', sizingMethod='scale')";k=e*Math.PI/180;e=Math.sin(k);k=Math.cos(k);e="progid:DXImageTransform.Microsoft.Matrix(M11="+k+",M12="+-e+",M21="+e+",M22="+k+",SizingMethod='auto expand')\n";
2928 (k=d.graphicOpacity||d.fillOpacity)&&1!=k&&(e+="progid:DXImageTransform.Microsoft.BasicImage(opacity="+k+")\n");a.style.filter=e;e=new OpenLayers.Geometry.Point(-b,-c);i=(new OpenLayers.Bounds(0,0,i,j)).toGeometry();i.rotate(d.rotation,e);i=i.getBounds();a.style.left=Math.round(parseInt(a.style.left)+i.left)+"px";a.style.top=Math.round(parseInt(a.style.top)-i.bottom)+"px"}},postDraw:function(a){a.style.visibility="visible";var b=a._style.fillColor,c=a._style.strokeColor;"none"==b&&a.fillcolor!=b&&
2929 (a.fillcolor=b);"none"==c&&a.strokecolor!=c&&(a.strokecolor=c)},setNodeDimension:function(a,b){var c=b.getBounds();if(c){var d=this.getResolution(),c=new OpenLayers.Bounds((c.left-this.featureDx)/d-this.offset.x|0,c.bottom/d-this.offset.y|0,(c.right-this.featureDx)/d-this.offset.x|0,c.top/d-this.offset.y|0);a.style.left=c.left+"px";a.style.top=c.top+"px";a.style.width=c.getWidth()+"px";a.style.height=c.getHeight()+"px";a.coordorigin=c.left+" "+c.top;a.coordsize=c.getWidth()+" "+c.getHeight()}},dashStyle:function(a){a=
2930 a.strokeDashstyle;switch(a){case "solid":case "dot":case "dash":case "dashdot":case "longdash":case "longdashdot":return a;default:return a=a.split(/[ ,]/),2==a.length?1*a[0]>=2*a[1]?"longdash":1==a[0]||1==a[1]?"dot":"dash":4==a.length?1*a[0]>=2*a[1]?"longdashdot":"dashdot":"solid"}},createNode:function(a,b){var c=document.createElement(a);b&&(c.id=b);c.unselectable="on";c.onselectstart=OpenLayers.Function.False;return c},nodeTypeCompare:function(a,b){var c=b,d=c.indexOf(":");-1!=d&&(c=c.substr(d+
2931 1));var e=a.nodeName,d=e.indexOf(":");-1!=d&&(e=e.substr(d+1));return c==e},createRenderRoot:function(){return this.nodeFactory(this.container.id+"_vmlRoot","div")},createRoot:function(a){return this.nodeFactory(this.container.id+a,"olv:group")},drawPoint:function(a,b){return this.drawCircle(a,b,1)},drawCircle:function(a,b,c){if(!isNaN(b.x)&&!isNaN(b.y)){var d=this.getResolution();a.style.left=((b.x-this.featureDx)/d-this.offset.x|0)-c+"px";a.style.top=(b.y/d-this.offset.y|0)-c+"px";b=2*c;a.style.width=
2932 b+"px";a.style.height=b+"px";return a}return!1},drawLineString:function(a,b){return this.drawLine(a,b,!1)},drawLinearRing:function(a,b){return this.drawLine(a,b,!0)},drawLine:function(a,b,c){this.setNodeDimension(a,b);for(var d=this.getResolution(),e=b.components.length,f=Array(e),g,h,i=0;i<e;i++)g=b.components[i],h=(g.x-this.featureDx)/d-this.offset.x|0,g=g.y/d-this.offset.y|0,f[i]=" "+h+","+g+" l ";a.path="m"+f.join("")+(c?" x e":" e");return a},drawPolygon:function(a,b){this.setNodeDimension(a,
2933 b);var c=this.getResolution(),d=[],e,f,g,h,i,j,k,l,m,n;e=0;for(f=b.components.length;e<f;e++){d.push("m");g=b.components[e].components;h=0===e;j=i=null;k=0;for(l=g.length;k<l;k++)m=g[k],n=(m.x-this.featureDx)/c-this.offset.x|0,m=m.y/c-this.offset.y|0,n=" "+n+","+m,d.push(n),0==k&&d.push(" l"),h||(i?i!=n&&(j?j!=n&&(h=!0):j=n):i=n);d.push(h?" x ":" ")}d.push("e");a.path=d.join("");return a},drawRectangle:function(a,b){var c=this.getResolution();a.style.left=((b.x-this.featureDx)/c-this.offset.x|0)+
2934 "px";a.style.top=(b.y/c-this.offset.y|0)+"px";a.style.width=(b.width/c|0)+"px";a.style.height=(b.height/c|0)+"px";return a},drawText:function(a,b,c){var d=this.nodeFactory(a+this.LABEL_ID_SUFFIX,"olv:rect"),e=this.nodeFactory(a+this.LABEL_ID_SUFFIX+"_textbox","olv:textbox"),f=this.getResolution();d.style.left=((c.x-this.featureDx)/f-this.offset.x|0)+"px";d.style.top=(c.y/f-this.offset.y|0)+"px";d.style.flip="y";e.innerText=b.label;"inherit"!=b.cursor&&null!=b.cursor&&(e.style.cursor=b.cursor);b.fontColor&&
2935 (e.style.color=b.fontColor);b.fontOpacity&&(e.style.filter="alpha(opacity="+100*b.fontOpacity+")");b.fontFamily&&(e.style.fontFamily=b.fontFamily);b.fontSize&&(e.style.fontSize=b.fontSize);b.fontWeight&&(e.style.fontWeight=b.fontWeight);b.fontStyle&&(e.style.fontStyle=b.fontStyle);!0===b.labelSelect&&(d._featureId=a,e._featureId=a,e._geometry=c,e._geometryClass=c.CLASS_NAME);e.style.whiteSpace="nowrap";e.inset="1px,0px,0px,0px";d.parentNode||(d.appendChild(e),this.textRoot.appendChild(d));b=b.labelAlign||
2936 "cm";1==b.length&&(b+="m");a=e.clientWidth*OpenLayers.Renderer.VML.LABEL_SHIFT[b.substr(0,1)];e=e.clientHeight*OpenLayers.Renderer.VML.LABEL_SHIFT[b.substr(1,1)];d.style.left=parseInt(d.style.left)-a-1+"px";d.style.top=parseInt(d.style.top)+e+"px"},moveRoot:function(a){var b=this.map.getLayer(a.container.id);b instanceof OpenLayers.Layer.Vector.RootContainer&&(b=this.map.getLayer(this.container.id));b&&b.renderer.clear();OpenLayers.Renderer.Elements.prototype.moveRoot.apply(this,arguments);b&&b.redraw()},
2937 importSymbol:function(a){var b=this.container.id+"-"+a,c=this.symbolCache[b];if(c)return c;c=OpenLayers.Renderer.symbol[a];if(!c)throw Error(a+" is not a valid symbol name");for(var a=new OpenLayers.Bounds(Number.MAX_VALUE,Number.MAX_VALUE,0,0),d=["m"],e=0;e<c.length;e+=2){var f=c[e],g=c[e+1];a.left=Math.min(a.left,f);a.bottom=Math.min(a.bottom,g);a.right=Math.max(a.right,f);a.top=Math.max(a.top,g);d.push(f);d.push(g);0==e&&d.push("l")}d.push("x e");c=d.join(" ");d=(a.getWidth()-a.getHeight())/2;
2938 0<d?(a.bottom-=d,a.top+=d):(a.left+=d,a.right-=d);c={path:c,size:a.getWidth(),left:a.left,bottom:a.bottom};return this.symbolCache[b]=c},CLASS_NAME:"OpenLayers.Renderer.VML"});OpenLayers.Renderer.VML.LABEL_SHIFT={l:0,c:0.5,r:1,t:0,m:0.5,b:1};OpenLayers.Control.CacheRead=OpenLayers.Class(OpenLayers.Control,{fetchEvent:"tileloadstart",layers:null,autoActivate:!0,setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);var b,c=this.layers||a.layers;for(b=c.length-1;0<=b;--b)this.addLayer({layer:c[b]});if(!this.layers)a.events.on({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this})},addLayer:function(a){a.layer.events.register(this.fetchEvent,this,this.fetch)},removeLayer:function(a){a.layer.events.unregister(this.fetchEvent,
2939 this,this.fetch)},fetch:function(a){if(this.active&&window.localStorage&&a.tile instanceof OpenLayers.Tile.Image){var b=a.tile,c=b.url;!b.layer.crossOriginKeyword&&(OpenLayers.ProxyHost&&0===c.indexOf(OpenLayers.ProxyHost))&&(c=OpenLayers.Control.CacheWrite.urlMap[c]);if(c=window.localStorage.getItem("olCache_"+c))b.url=c,"tileerror"===a.type&&b.setImgSrc(c)}},destroy:function(){if(this.layers||this.map){var a,b=this.layers||this.map.layers;for(a=b.length-1;0<=a;--a)this.removeLayer({layer:b[a]})}this.map&&
2940 this.map.events.un({addlayer:this.addLayer,removeLayer:this.removeLayer,scope:this});OpenLayers.Control.prototype.destroy.apply(this,arguments)},CLASS_NAME:"OpenLayers.Control.CacheRead"});OpenLayers.Protocol.WFS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.0.0",CLASS_NAME:"OpenLayers.Protocol.WFS.v1_0_0"});OpenLayers.Format.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Format.XML,{layerIdentifier:"_layer",featureIdentifier:"_feature",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},gmlFormat:null,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));var b=a.documentElement;if(b)var c=this["read_"+b.nodeName],a=c?c.call(this,b):(new OpenLayers.Format.GML(this.options?this.options:{})).read(a);return a},read_msGMLOutput:function(a){var b=
2941 [];if(a=this.getSiblingNodesByTagCriteria(a,this.layerIdentifier))for(var c=0,d=a.length;c<d;++c){var e=a[c],f=e.nodeName;e.prefix&&(f=f.split(":")[1]);f=f.replace(this.layerIdentifier,"");if(e=this.getSiblingNodesByTagCriteria(e,this.featureIdentifier))for(var g=0;g<e.length;g++){var h=e[g],i=this.parseGeometry(h),h=this.parseAttributes(h),h=new OpenLayers.Feature.Vector(i.geometry,h,null);h.bounds=i.bounds;h.type=f;b.push(h)}}return b},read_FeatureInfoResponse:function(a){for(var b=[],a=this.getElementsByTagNameNS(a,
2942 "*","FIELDS"),c=0,d=a.length;c<d;c++){var e=a[c],f={},g,h=e.attributes.length;if(0<h)for(g=0;g<h;g++){var i=e.attributes[g];f[i.nodeName]=i.nodeValue}else{e=e.childNodes;g=0;for(h=e.length;g<h;++g)i=e[g],3!=i.nodeType&&(f[i.getAttribute("name")]=i.getAttribute("value"))}b.push(new OpenLayers.Feature.Vector(null,f,null))}return b},getSiblingNodesByTagCriteria:function(a,b){var c=[],d,e,f,g;if(a&&a.hasChildNodes()){d=a.childNodes;f=d.length;for(var h=0;h<f;h++){for(g=d[h];g&&1!=g.nodeType;)g=g.nextSibling,
2943 h++;e=g?g.nodeName:"";0<e.length&&-1<e.indexOf(b)?c.push(g):(e=this.getSiblingNodesByTagCriteria(g,b),0<e.length&&(0==c.length?c=e:c.push(e)))}}return c},parseAttributes:function(a){var b={};if(1==a.nodeType)for(var a=a.childNodes,c=a.length,d=0;d<c;++d){var e=a[d];if(1==e.nodeType){var f=e.childNodes,e=e.prefix?e.nodeName.split(":")[1]:e.nodeName;if(0==f.length)b[e]=null;else if(1==f.length&&(f=f[0],3==f.nodeType||4==f.nodeType))f=f.nodeValue.replace(this.regExes.trimSpace,""),b[e]=f}}return b},
2944 parseGeometry:function(a){this.gmlFormat||(this.gmlFormat=new OpenLayers.Format.GML);var a=this.gmlFormat.parseFeature(a),b,c=null;a&&(b=a.geometry&&a.geometry.clone(),c=a.bounds&&a.bounds.clone(),a.destroy());return{geometry:b,bounds:c}},CLASS_NAME:"OpenLayers.Format.WMSGetFeatureInfo"});OpenLayers.Control.WMTSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:!1,requestEncoding:"KVP",drillDown:!1,maxFeatures:10,clickCallback:"click",layers:null,queryVisible:!0,infoFormat:"text/html",vendorParams:{},format:null,formatOptions:null,handlerOptions:null,handler:null,hoverRequest:null,pending:0,initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.format||(this.format=new OpenLayers.Format.WMSGetFeatureInfo(a.formatOptions));
2945 !0===this.drillDown&&(this.hover=!1);this.hover?this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250})):(a={},a[this.clickCallback]=this.getInfoForClick,this.handler=new OpenLayers.Handler.Click(this,a,this.handlerOptions.click||{}))},getInfoForClick:function(a){this.request(a.xy,{})},getInfoForHover:function(a){this.request(a.xy,{hover:!0})},cancelHover:function(){this.hoverRequest&&(--this.pending,
2946 0>=this.pending&&(OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"),this.pending=0),this.hoverRequest.abort(),this.hoverRequest=null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d=a.length-1;0<=d;--d)if(c=a[d],c instanceof OpenLayers.Layer.WMTS&&c.requestEncoding===this.requestEncoding&&(!this.queryVisible||c.getVisibility()))if(b.push(c),!this.drillDown||this.hover)break;return b},buildRequestOptions:function(a,b){var c=this.map.getLonLatFromPixel(b),d=
2947 a.getURL(new OpenLayers.Bounds(c.lon,c.lat,c.lon,c.lat)),d=OpenLayers.Util.getParameters(d),c=a.getTileInfo(c);OpenLayers.Util.extend(d,{service:"WMTS",version:a.version,request:"GetFeatureInfo",infoFormat:this.infoFormat,i:c.i,j:c.j});OpenLayers.Util.applyDefaults(d,this.vendorParams);return{url:OpenLayers.Util.isArray(a.url)?a.url[0]:a.url,params:OpenLayers.Util.upperCaseObject(d),callback:function(c){this.handleResponse(b,c,a)},scope:this}},request:function(a,b){var b=b||{},c=this.findLayers();
2948 if(0<c.length){for(var d,e,f=0,g=c.length;f<g;f++)e=c[f],d=this.events.triggerEvent("beforegetfeatureinfo",{xy:a,layer:e}),!1!==d&&(++this.pending,d=this.buildRequestOptions(e,a),d=OpenLayers.Request.GET(d),!0===b.hover&&(this.hoverRequest=d));0<this.pending&&OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait")}},handleResponse:function(a,b,c){--this.pending;0>=this.pending&&(OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait"),this.pending=0);if(b.status&&(200>b.status||
2949 300<=b.status))this.events.triggerEvent("exception",{xy:a,request:b,layer:c});else{var d=b.responseXML;if(!d||!d.documentElement)d=b.responseText;var e,f;try{e=this.format.read(d)}catch(g){f=!0,this.events.triggerEvent("exception",{xy:a,request:b,error:g,layer:c})}f||this.events.triggerEvent("getfeatureinfo",{text:b.responseText,features:e,request:b,xy:a,layer:c})}},CLASS_NAME:"OpenLayers.Control.WMTSGetFeatureInfo"});OpenLayers.Strategy.Paging=OpenLayers.Class(OpenLayers.Strategy,{features:null,length:10,num:null,paging:!1,activate:function(){var a=OpenLayers.Strategy.prototype.activate.call(this);if(a)this.layer.events.on({beforefeaturesadded:this.cacheFeatures,scope:this});return a},deactivate:function(){var a=OpenLayers.Strategy.prototype.deactivate.call(this);a&&(this.clearCache(),this.layer.events.un({beforefeaturesadded:this.cacheFeatures,scope:this}));return a},cacheFeatures:function(a){this.paging||(this.clearCache(),
2950 this.features=a.features,this.pageNext(a))},clearCache:function(){if(this.features)for(var a=0;a<this.features.length;++a)this.features[a].destroy();this.num=this.features=null},pageCount:function(){return Math.ceil((this.features?this.features.length:0)/this.length)},pageNum:function(){return this.num},pageLength:function(a){a&&0<a&&(this.length=a);return this.length},pageNext:function(a){var b=!1;this.features&&(null===this.num&&(this.num=-1),b=this.page((this.num+1)*this.length,a));return b},pagePrevious:function(){var a=
2951 !1;this.features&&(null===this.num&&(this.num=this.pageCount()),a=this.page((this.num-1)*this.length));return a},page:function(a,b){var c=!1;if(this.features&&0<=a&&a<this.features.length){var d=Math.floor(a/this.length);d!=this.num&&(this.paging=!0,c=this.features.slice(a,a+this.length),this.layer.removeFeatures(this.layer.features),this.num=d,b&&b.features?b.features=c:this.layer.addFeatures(c),this.paging=!1,c=!0)}return c},CLASS_NAME:"OpenLayers.Strategy.Paging"});OpenLayers.Protocol.CSW.v2_0_2=OpenLayers.Class(OpenLayers.Protocol,{formatOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=new OpenLayers.Format.CSWGetRecords.v2_0_2(OpenLayers.Util.extend({},this.formatOptions)))},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,
2952 this.options||{});var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.format.write(a.params);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),params:a.params,headers:a.headers,data:c});return b},handleRead:function(a,b){if(b.callback){var c=a.priv;200<=c.status&&300>c.status?(a.data=this.parseData(c),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE;b.callback.call(b.scope,a)}},parseData:function(a){var b=
2953 a.responseXML;if(!b||!b.documentElement)b=a.responseText;return!b||0>=b.length?null:this.format.read(b)},CLASS_NAME:"OpenLayers.Protocol.CSW.v2_0_2"});OpenLayers.Format.WMSCapabilities.v1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1,{readers:{wms:OpenLayers.Util.applyDefaults({WMT_MS_Capabilities:function(a,b){this.readChildNodes(a,b)},Keyword:function(a,b){b.keywords&&b.keywords.push(this.getChildValue(a))},DescribeLayer:function(a,b){b.describelayer={formats:[]};this.readChildNodes(a,b.describelayer)},GetLegendGraphic:function(a,b){b.getlegendgraphic={formats:[]};this.readChildNodes(a,b.getlegendgraphic)},GetStyles:function(a,b){b.getstyles=
2954 {formats:[]};this.readChildNodes(a,b.getstyles)},PutStyles:function(a,b){b.putstyles={formats:[]};this.readChildNodes(a,b.putstyles)},UserDefinedSymbolization:function(a,b){var c={supportSLD:1==parseInt(a.getAttribute("SupportSLD")),userLayer:1==parseInt(a.getAttribute("UserLayer")),userStyle:1==parseInt(a.getAttribute("UserStyle")),remoteWFS:1==parseInt(a.getAttribute("RemoteWFS"))};b.userSymbols=c},LatLonBoundingBox:function(a,b){b.llbbox=[parseFloat(a.getAttribute("minx")),parseFloat(a.getAttribute("miny")),
2955 parseFloat(a.getAttribute("maxx")),parseFloat(a.getAttribute("maxy"))]},BoundingBox:function(a,b){var c=OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms.BoundingBox.apply(this,[a,b]);c.srs=a.getAttribute("SRS");b.bbox[c.srs]=c},ScaleHint:function(a,b){var c=a.getAttribute("min"),d=a.getAttribute("max"),e=Math.pow(2,0.5),f=OpenLayers.INCHES_PER_UNIT.m;b.maxScale=parseFloat((c/e*f*OpenLayers.DOTS_PER_INCH).toPrecision(13));b.minScale=parseFloat((d/e*f*OpenLayers.DOTS_PER_INCH).toPrecision(13))},
2956 Dimension:function(a,b){var c={name:a.getAttribute("name").toLowerCase(),units:a.getAttribute("units"),unitsymbol:a.getAttribute("unitSymbol")};b.dimensions[c.name]=c},Extent:function(a,b){var c=a.getAttribute("name").toLowerCase();if(c in b.dimensions){c=b.dimensions[c];c.nearestVal="1"===a.getAttribute("nearestValue");c.multipleVal="1"===a.getAttribute("multipleValues");c.current="1"===a.getAttribute("current");c["default"]=a.getAttribute("default")||"";var d=this.getChildValue(a);c.values=d.split(",")}}},
2957 OpenLayers.Format.WMSCapabilities.v1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1"});OpenLayers.Control.Graticule=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,intervals:[45,30,20,10,5,2,1,0.5,0.2,0.1,0.05,0.01,0.005,0.002,0.001],displayInLayerSwitcher:!0,visible:!0,numPoints:50,targetSize:200,layerName:null,labelled:!0,labelFormat:"dm",lineSymbolizer:{strokeColor:"#333",strokeWidth:1,strokeOpacity:0.5},labelSymbolizer:{},gratLayer:null,initialize:function(a){a=a||{};a.layerName=a.layerName||OpenLayers.i18n("Graticule");OpenLayers.Control.prototype.initialize.apply(this,[a]);
2958 this.labelSymbolizer.stroke=!1;this.labelSymbolizer.fill=!1;this.labelSymbolizer.label="${label}";this.labelSymbolizer.labelAlign="${labelAlign}";this.labelSymbolizer.labelXOffset="${xOffset}";this.labelSymbolizer.labelYOffset="${yOffset}"},destroy:function(){this.deactivate();OpenLayers.Control.prototype.destroy.apply(this,arguments);this.gratLayer&&(this.gratLayer.destroy(),this.gratLayer=null)},draw:function(){OpenLayers.Control.prototype.draw.apply(this,arguments);if(!this.gratLayer){var a=new OpenLayers.Style({},
2959 {rules:[new OpenLayers.Rule({symbolizer:{Point:this.labelSymbolizer,Line:this.lineSymbolizer}})]});this.gratLayer=new OpenLayers.Layer.Vector(this.layerName,{styleMap:new OpenLayers.StyleMap({"default":a}),visibility:this.visible,displayInLayerSwitcher:this.displayInLayerSwitcher})}return this.div},activate:function(){return OpenLayers.Control.prototype.activate.apply(this,arguments)?(this.map.addLayer(this.gratLayer),this.map.events.register("moveend",this,this.update),this.update(),!0):!1},deactivate:function(){return OpenLayers.Control.prototype.deactivate.apply(this,
2960 arguments)?(this.map.events.unregister("moveend",this,this.update),this.map.removeLayer(this.gratLayer),!0):!1},update:function(){var a=this.map.getExtent();if(a){this.gratLayer.destroyFeatures();var b=new OpenLayers.Projection("EPSG:4326"),c=this.map.getProjectionObject(),d=this.map.getResolution();c.proj&&"longlat"==c.proj.projName&&(this.numPoints=1);var e=this.map.getCenter(),f=new OpenLayers.Pixel(e.lon,e.lat);OpenLayers.Projection.transform(f,c,b);for(var e=this.targetSize*d,e=e*e,g,d=0;d<this.intervals.length;++d){g=
2961 this.intervals[d];var h=g/2,i=f.offset({x:-h,y:-h}),h=f.offset({x:h,y:h});OpenLayers.Projection.transform(i,b,c);OpenLayers.Projection.transform(h,b,c);if((i.x-h.x)*(i.x-h.x)+(i.y-h.y)*(i.y-h.y)<=e)break}f.x=Math.floor(f.x/g)*g;f.y=Math.floor(f.y/g)*g;var d=0,e=[f.clone()],h=f.clone(),j;do h=h.offset({x:0,y:g}),j=OpenLayers.Projection.transform(h.clone(),b,c),e.unshift(h);while(a.containsPixel(j)&&1E3>++d);h=f.clone();do h=h.offset({x:0,y:-g}),j=OpenLayers.Projection.transform(h.clone(),b,c),e.push(h);
2962 while(a.containsPixel(j)&&1E3>++d);d=0;i=[f.clone()];h=f.clone();do h=h.offset({x:-g,y:0}),j=OpenLayers.Projection.transform(h.clone(),b,c),i.unshift(h);while(a.containsPixel(j)&&1E3>++d);h=f.clone();do h=h.offset({x:g,y:0}),j=OpenLayers.Projection.transform(h.clone(),b,c),i.push(h);while(a.containsPixel(j)&&1E3>++d);g=[];for(d=0;d<i.length;++d){j=i[d].x;for(var f=[],k=null,l=Math.min(e[0].y,90),h=Math.max(e[e.length-1].y,-90),m=(l-h)/this.numPoints,l=h,h=0;h<=this.numPoints;++h){var n=new OpenLayers.Geometry.Point(j,
2963 l);n.transform(b,c);f.push(n);l+=m;n.y>=a.bottom&&!k&&(k=n)}this.labelled&&(k=new OpenLayers.Geometry.Point(k.x,a.bottom),j={value:j,label:this.labelled?OpenLayers.Util.getFormattedLonLat(j,"lon",this.labelFormat):"",labelAlign:"cb",xOffset:0,yOffset:2},this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(k,j)));f=new OpenLayers.Geometry.LineString(f);g.push(new OpenLayers.Feature.Vector(f))}for(h=0;h<e.length;++h)if(l=e[h].y,!(-90>l||90<l)){f=[];d=i[0].x;m=(i[i.length-1].x-d)/this.numPoints;
2964 j=d;k=null;for(d=0;d<=this.numPoints;++d)n=new OpenLayers.Geometry.Point(j,l),n.transform(b,c),f.push(n),j+=m,n.x<a.right&&(k=n);this.labelled&&(k=new OpenLayers.Geometry.Point(a.right,k.y),j={value:l,label:this.labelled?OpenLayers.Util.getFormattedLonLat(l,"lat",this.labelFormat):"",labelAlign:"rb",xOffset:-2,yOffset:2},this.gratLayer.addFeatures(new OpenLayers.Feature.Vector(k,j)));f=new OpenLayers.Geometry.LineString(f);g.push(new OpenLayers.Feature.Vector(f))}this.gratLayer.addFeatures(g)}},CLASS_NAME:"OpenLayers.Control.Graticule"});OpenLayers.Layer.UTFGrid=OpenLayers.Class(OpenLayers.Layer.XYZ,{isBaseLayer:!1,projection:new OpenLayers.Projection("EPSG:900913"),useJSONP:!1,tileClass:OpenLayers.Tile.UTFGrid,initialize:function(a){OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a.name,a.url,{},a]);this.tileOptions=OpenLayers.Util.extend({utfgridResolution:this.utfgridResolution},this.tileOptions)},clone:function(a){null==a&&(a=new OpenLayers.Layer.UTFGrid(this.getOptions()));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,
2965 [a])},getFeatureInfo:function(a){var b=null,a=this.getTileData(a);a.tile&&(b=a.tile.getFeatureInfo(a.i,a.j));return b},getFeatureId:function(a){var b=null,a=this.getTileData(a);a.tile&&(b=a.tile.getFeatureId(a.i,a.j));return b},CLASS_NAME:"OpenLayers.Layer.UTFGrid"});OpenLayers.Layer.ArcGISCache=OpenLayers.Class(OpenLayers.Layer.XYZ,{url:null,tileOrigin:null,tileSize:new OpenLayers.Size(256,256),useArcGISServer:!0,type:"png",useScales:!1,overrideDPI:!1,initialize:function(a,b,c){OpenLayers.Layer.XYZ.prototype.initialize.apply(this,arguments);this.resolutions&&(this.serverResolutions=this.resolutions,this.maxExtent=this.getMaxExtentForResolution(this.resolutions[0]));if(this.layerInfo){var d=this.layerInfo,e=new OpenLayers.Bounds(d.fullExtent.xmin,d.fullExtent.ymin,
2966 d.fullExtent.xmax,d.fullExtent.ymax);this.projection="EPSG:"+d.spatialReference.wkid;this.sphericalMercator=102100==d.spatialReference.wkid;this.units="esriFeet"==d.units?"ft":"m";if(d.tileInfo){this.tileSize=new OpenLayers.Size(d.tileInfo.width||d.tileInfo.cols,d.tileInfo.height||d.tileInfo.rows);this.tileOrigin=new OpenLayers.LonLat(d.tileInfo.origin.x,d.tileInfo.origin.y);var f=new OpenLayers.Geometry.Point(e.left,e.top),e=new OpenLayers.Geometry.Point(e.right,e.bottom);this.useScales?this.scales=
2967 []:this.resolutions=[];this.lods=[];for(var g in d.tileInfo.lods)if(d.tileInfo.lods.hasOwnProperty(g)){var h=d.tileInfo.lods[g];this.useScales?this.scales.push(h.scale):this.resolutions.push(h.resolution);var i=this.getContainingTileCoords(f,h.resolution);h.startTileCol=i.x;h.startTileRow=i.y;i=this.getContainingTileCoords(e,h.resolution);h.endTileCol=i.x;h.endTileRow=i.y;this.lods.push(h)}this.maxExtent=this.calculateMaxExtentWithLOD(this.lods[0]);this.serverResolutions=this.resolutions;this.overrideDPI&&
2968 d.tileInfo.dpi&&(OpenLayers.DOTS_PER_INCH=d.tileInfo.dpi)}}},getContainingTileCoords:function(a,b){return new OpenLayers.Pixel(Math.max(Math.floor((a.x-this.tileOrigin.lon)/(this.tileSize.w*b)),0),Math.max(Math.floor((this.tileOrigin.lat-a.y)/(this.tileSize.h*b)),0))},calculateMaxExtentWithLOD:function(a){var b=this.tileOrigin.lon+a.startTileCol*this.tileSize.w*a.resolution,c=this.tileOrigin.lat-a.startTileRow*this.tileSize.h*a.resolution;return new OpenLayers.Bounds(b,c-(a.endTileRow-a.startTileRow+
2969 1)*this.tileSize.h*a.resolution,b+(a.endTileCol-a.startTileCol+1)*this.tileSize.w*a.resolution,c)},calculateMaxExtentWithExtent:function(a,b){var c=new OpenLayers.Geometry.Point(a.left,a.top),d=new OpenLayers.Geometry.Point(a.right,a.bottom),c=this.getContainingTileCoords(c,b),d=this.getContainingTileCoords(d,b);return this.calculateMaxExtentWithLOD({resolution:b,startTileCol:c.x,startTileRow:c.y,endTileCol:d.x,endTileRow:d.y})},getUpperLeftTileCoord:function(a){return this.getContainingTileCoords(new OpenLayers.Geometry.Point(this.maxExtent.left,
2970 this.maxExtent.top),a)},getLowerRightTileCoord:function(a){return this.getContainingTileCoords(new OpenLayers.Geometry.Point(this.maxExtent.right,this.maxExtent.bottom),a)},getMaxExtentForResolution:function(a){var b=this.getUpperLeftTileCoord(a),c=this.getLowerRightTileCoord(a),d=this.tileOrigin.lon+b.x*this.tileSize.w*a,e=this.tileOrigin.lat-b.y*this.tileSize.h*a;return new OpenLayers.Bounds(d,e-(c.y-b.y+1)*this.tileSize.h*a,d+(c.x-b.x+1)*this.tileSize.w*a,e)},clone:function(a){null==a&&(a=new OpenLayers.Layer.ArcGISCache(this.name,
2971 this.url,this.options));return OpenLayers.Layer.XYZ.prototype.clone.apply(this,[a])},getMaxExtent:function(){return this.maxExtent=this.getMaxExtentForResolution(this.map.getResolution())},getTileOrigin:function(){var a=this.getMaxExtent();return new OpenLayers.LonLat(a.left,a.bottom)},getURL:function(a){var b=this.getResolution(),c=this.tileOrigin.lon+b*this.tileSize.w/2,d=this.tileOrigin.lat-b*this.tileSize.h/2,a=a.getCenterLonLat(),c=Math.round(Math.abs((a.lon-c)/(b*this.tileSize.w))),d=Math.round(Math.abs((d-
2972 a.lat)/(b*this.tileSize.h))),a=this.map.getZoom();if(this.lods){if(b=this.lods[this.map.getZoom()],c<b.startTileCol||c>b.endTileCol||d<b.startTileRow||d>b.endTileRow)return null}else{var e=this.getUpperLeftTileCoord(b),b=this.getLowerRightTileCoord(b);if(c<e.x||c>=b.x||d<e.y||d>=b.y)return null}b=this.url;e=""+c+d+a;OpenLayers.Util.isArray(b)&&(b=this.selectUrl(e,b));this.useArcGISServer?b+="/tile/${z}/${y}/${x}":(c="C"+this.zeroPad(c,8,16),d="R"+this.zeroPad(d,8,16),a="L"+this.zeroPad(a,2,16),b=
2973 b+"/${z}/${y}/${x}."+this.type);b=OpenLayers.String.format(b,{x:c,y:d,z:a});return OpenLayers.Util.urlAppend(b,OpenLayers.Util.getParameterString(this.params))},zeroPad:function(a,b,c){for(a=a.toString(c||10);a.length<b;)a="0"+a;return a},CLASS_NAME:"OpenLayers.Layer.ArcGISCache"});OpenLayers.Control.WMSGetFeatureInfo=OpenLayers.Class(OpenLayers.Control,{hover:!1,drillDown:!1,maxFeatures:10,clickCallback:"click",output:"features",layers:null,queryVisible:!1,url:null,layerUrls:null,infoFormat:"text/html",vendorParams:{},format:null,formatOptions:null,handlerOptions:null,handler:null,hoverRequest:null,initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||{};OpenLayers.Control.prototype.initialize.apply(this,[a]);this.format||(this.format=new OpenLayers.Format.WMSGetFeatureInfo(a.formatOptions));
2974 !0===this.drillDown&&(this.hover=!1);this.hover?this.handler=new OpenLayers.Handler.Hover(this,{move:this.cancelHover,pause:this.getInfoForHover},OpenLayers.Util.extend(this.handlerOptions.hover||{},{delay:250})):(a={},a[this.clickCallback]=this.getInfoForClick,this.handler=new OpenLayers.Handler.Click(this,a,this.handlerOptions.click||{}))},getInfoForClick:function(a){this.events.triggerEvent("beforegetfeatureinfo",{xy:a.xy});OpenLayers.Element.addClass(this.map.viewPortDiv,"olCursorWait");this.request(a.xy,
2975 {})},getInfoForHover:function(a){this.events.triggerEvent("beforegetfeatureinfo",{xy:a.xy});this.request(a.xy,{hover:!0})},cancelHover:function(){this.hoverRequest&&(this.hoverRequest.abort(),this.hoverRequest=null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d,e=a.length-1;0<=e;--e)if(c=a[e],c instanceof OpenLayers.Layer.WMS&&(!this.queryVisible||c.getVisibility()))d=OpenLayers.Util.isArray(c.url)?c.url[0]:c.url,!1===this.drillDown&&!this.url&&(this.url=d),(!0===this.drillDown||
2976 this.urlMatches(d))&&b.push(c);return b},urlMatches:function(a){var b=OpenLayers.Util.isEquivalentUrl(this.url,a);if(!b&&this.layerUrls)for(var c=0,d=this.layerUrls.length;c<d;++c)if(OpenLayers.Util.isEquivalentUrl(this.layerUrls[c],a)){b=!0;break}return b},buildWMSOptions:function(a,b,c,d){for(var e=[],f=[],g=0,h=b.length;g<h;g++)null!=b[g].params.LAYERS&&(e=e.concat(b[g].params.LAYERS),f=f.concat(this.getStyleNames(b[g])));b=b[0];g=this.map.getProjection();(h=b.projection)&&h.equals(this.map.getProjectionObject())&&
2977 (g=h.getCode());d=OpenLayers.Util.extend({service:"WMS",version:b.params.VERSION,request:"GetFeatureInfo",exceptions:b.params.EXCEPTIONS,bbox:this.map.getExtent().toBBOX(null,b.reverseAxisOrder()),feature_count:this.maxFeatures,height:this.map.getSize().h,width:this.map.getSize().w,format:d,info_format:b.params.INFO_FORMAT||this.infoFormat},1.3<=parseFloat(b.params.VERSION)?{crs:g,i:parseInt(c.x),j:parseInt(c.y)}:{srs:g,x:parseInt(c.x),y:parseInt(c.y)});0!=e.length&&(d=OpenLayers.Util.extend({layers:e,
2978 query_layers:e,styles:f},d));OpenLayers.Util.applyDefaults(d,this.vendorParams);return{url:a,params:OpenLayers.Util.upperCaseObject(d),callback:function(b){this.handleResponse(c,b,a)},scope:this}},getStyleNames:function(a){return a.params.STYLES?a.params.STYLES:OpenLayers.Util.isArray(a.params.LAYERS)?Array(a.params.LAYERS.length):a.params.LAYERS.replace(/[^,]/g,"")},request:function(a,b){var c=this.findLayers();if(0==c.length)this.events.triggerEvent("nogetfeatureinfo"),OpenLayers.Element.removeClass(this.map.viewPortDiv,
2979 "olCursorWait");else if(b=b||{},!1===this.drillDown){var c=this.buildWMSOptions(this.url,c,a,c[0].params.FORMAT),d=OpenLayers.Request.GET(c);!0===b.hover&&(this.hoverRequest=d)}else{this._numRequests=this._requestCount=0;this.features=[];for(var d={},e,f=0,g=c.length;f<g;f++){var h=c[f];e=OpenLayers.Util.isArray(h.url)?h.url[0]:h.url;e in d?d[e].push(h):(this._numRequests++,d[e]=[h])}for(e in d)c=d[e],c=this.buildWMSOptions(e,c,a,c[0].params.FORMAT),OpenLayers.Request.GET(c)}},triggerGetFeatureInfo:function(a,
2980 b,c){this.events.triggerEvent("getfeatureinfo",{text:a.responseText,features:c,request:a,xy:b});OpenLayers.Element.removeClass(this.map.viewPortDiv,"olCursorWait")},handleResponse:function(a,b,c){var d=b.responseXML;if(!d||!d.documentElement)d=b.responseText;d=this.format.read(d);!1===this.drillDown?this.triggerGetFeatureInfo(b,a,d):(this._requestCount++,this._features="object"===this.output?(this._features||[]).concat({url:c,features:d}):(this._features||[]).concat(d),this._requestCount===this._numRequests&&
2981 (this.triggerGetFeatureInfo(b,a,this._features.concat()),delete this._features,delete this._requestCount,delete this._numRequests))},CLASS_NAME:"OpenLayers.Control.WMSGetFeatureInfo"});OpenLayers.Format.WMSCapabilities.v1_3_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_3,{version:"1.3.0",CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_3_0"});OpenLayers.Format.SOSGetFeatureOfInterest=OpenLayers.Class(OpenLayers.Format.XML,{VERSION:"1.0.0",namespaces:{sos:"http://www.opengis.net/sos/1.0",gml:"http://www.opengis.net/gml",sa:"http://www.opengis.net/sampling/1.0",xsi:"http://www.w3.org/2001/XMLSchema-instance"},schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosAll.xsd",defaultPrefix:"sos",regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},read:function(a){"string"==
2982 typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={features:[]};this.readNode(a,b);for(var a=[],c=0,d=b.features.length;c<d;c++){var e=b.features[c];this.internalProjection&&(this.externalProjection&&e.components[0])&&e.components[0].transform(this.externalProjection,this.internalProjection);e=new OpenLayers.Feature.Vector(e.components[0],e.attributes);a.push(e)}return a},readers:{sa:{SamplingPoint:function(a,b){if(!b.attributes){var c=
2983 {attributes:{}};b.features.push(c);b=c}b.attributes.id=this.getAttributeNS(a,this.namespaces.gml,"id");this.readChildNodes(a,b)},position:function(a,b){this.readChildNodes(a,b)}},gml:OpenLayers.Util.applyDefaults({FeatureCollection:function(a,b){this.readChildNodes(a,b)},featureMember:function(a,b){var c={attributes:{}};b.features.push(c);this.readChildNodes(a,c)},name:function(a,b){b.attributes.name=this.getChildValue(a)},pos:function(a,b){this.externalProjection||(this.externalProjection=new OpenLayers.Projection(a.getAttribute("srsName")));
2984 OpenLayers.Format.GML.v3.prototype.readers.gml.pos.apply(this,[a,b])}},OpenLayers.Format.GML.v3.prototype.readers.gml)},writers:{sos:{GetFeatureOfInterest:function(a){for(var b=this.createElementNSPlus("GetFeatureOfInterest",{attributes:{version:this.VERSION,service:"SOS","xsi:schemaLocation":this.schemaLocation}}),c=0,d=a.fois.length;c<d;c++)this.writeNode("FeatureOfInterestId",{foi:a.fois[c]},b);return b},FeatureOfInterestId:function(a){return this.createElementNSPlus("FeatureOfInterestId",{value:a.foi})}}},
2985 CLASS_NAME:"OpenLayers.Format.SOSGetFeatureOfInterest"});OpenLayers.Format.SOSGetObservation=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{ows:"http://www.opengis.net/ows",gml:"http://www.opengis.net/gml",sos:"http://www.opengis.net/sos/1.0",ogc:"http://www.opengis.net/ogc",om:"http://www.opengis.net/om/1.0",sa:"http://www.opengis.net/sampling/1.0",xlink:"http://www.w3.org/1999/xlink",xsi:"http://www.w3.org/2001/XMLSchema-instance"},regExes:{trimSpace:/^\s*|\s*$/g,removeSpace:/\s*/g,splitSpace:/\s+/,trimComma:/\s*,\s*/g},VERSION:"1.0.0",schemaLocation:"http://www.opengis.net/sos/1.0 http://schemas.opengis.net/sos/1.0.0/sosGetObservation.xsd",
2986 defaultPrefix:"sos",read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={measurements:[],observations:[]};this.readNode(a,b);return b},write:function(a){a=this.writeNode("sos:GetObservation",a);a.setAttribute("xmlns:om",this.namespaces.om);a.setAttribute("xmlns:ogc",this.namespaces.ogc);this.setAttributeNS(a,this.namespaces.xsi,"xsi:schemaLocation",this.schemaLocation);return OpenLayers.Format.XML.prototype.write.apply(this,
2987 [a])},readers:{om:{ObservationCollection:function(a,b){b.id=this.getAttributeNS(a,this.namespaces.gml,"id");this.readChildNodes(a,b)},member:function(a,b){this.readChildNodes(a,b)},Measurement:function(a,b){var c={};b.measurements.push(c);this.readChildNodes(a,c)},Observation:function(a,b){var c={};b.observations.push(c);this.readChildNodes(a,c)},samplingTime:function(a,b){var c={};b.samplingTime=c;this.readChildNodes(a,c)},observedProperty:function(a,b){b.observedProperty=this.getAttributeNS(a,this.namespaces.xlink,
2988 "href");this.readChildNodes(a,b)},procedure:function(a,b){b.procedure=this.getAttributeNS(a,this.namespaces.xlink,"href");this.readChildNodes(a,b)},featureOfInterest:function(a,b){var c={features:[]};b.fois=[];b.fois.push(c);this.readChildNodes(a,c);for(var d=[],e=0,f=c.features.length;e<f;e++){var g=c.features[e];d.push(new OpenLayers.Feature.Vector(g.components[0],g.attributes))}c.features=d},result:function(a,b){var c={};b.result=c;""!==this.getChildValue(a)?(c.value=this.getChildValue(a),c.uom=
2989 a.getAttribute("uom")):this.readChildNodes(a,c)}},sa:OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.sa,gml:OpenLayers.Util.applyDefaults({TimeInstant:function(a,b){var c={};b.timeInstant=c;this.readChildNodes(a,c)},timePosition:function(a,b){b.timePosition=this.getChildValue(a)}},OpenLayers.Format.SOSGetFeatureOfInterest.prototype.readers.gml)},writers:{sos:{GetObservation:function(a){var b=this.createElementNSPlus("GetObservation",{attributes:{version:this.VERSION,service:"SOS"}});this.writeNode("offering",
2990 a,b);a.eventTime&&this.writeNode("eventTime",a,b);for(var c in a.procedures)this.writeNode("procedure",a.procedures[c],b);for(var d in a.observedProperties)this.writeNode("observedProperty",a.observedProperties[d],b);a.foi&&this.writeNode("featureOfInterest",a.foi,b);this.writeNode("responseFormat",a,b);a.resultModel&&this.writeNode("resultModel",a,b);a.responseMode&&this.writeNode("responseMode",a,b);return b},featureOfInterest:function(a){var b=this.createElementNSPlus("featureOfInterest");this.writeNode("ObjectID",
2991 a.objectId,b);return b},ObjectID:function(a){return this.createElementNSPlus("ObjectID",{value:a})},responseFormat:function(a){return this.createElementNSPlus("responseFormat",{value:a.responseFormat})},procedure:function(a){return this.createElementNSPlus("procedure",{value:a})},offering:function(a){return this.createElementNSPlus("offering",{value:a.offering})},observedProperty:function(a){return this.createElementNSPlus("observedProperty",{value:a})},eventTime:function(a){var b=this.createElementNSPlus("eventTime");
2992 "latest"===a.eventTime&&this.writeNode("ogc:TM_Equals",a,b);return b},resultModel:function(a){return this.createElementNSPlus("resultModel",{value:a.resultModel})},responseMode:function(a){return this.createElementNSPlus("responseMode",{value:a.responseMode})}},ogc:{TM_Equals:function(a){var b=this.createElementNSPlus("ogc:TM_Equals");this.writeNode("ogc:PropertyName",{property:"urn:ogc:data:time:iso8601"},b);"latest"===a.eventTime&&this.writeNode("gml:TimeInstant",{value:"latest"},b);return b},PropertyName:function(a){return this.createElementNSPlus("ogc:PropertyName",
2993 {value:a.property})}},gml:{TimeInstant:function(a){var b=this.createElementNSPlus("gml:TimeInstant");this.writeNode("gml:timePosition",a,b);return b},timePosition:function(a){return this.createElementNSPlus("gml:timePosition",{value:a.value})}}},CLASS_NAME:"OpenLayers.Format.SOSGetObservation"});OpenLayers.Control.UTFGrid=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,layers:null,defaultHandlerOptions:{delay:300,pixelTolerance:4,stopMove:!1,single:!0,"double":!1,stopSingle:!1,stopDouble:!1},handlerMode:"click",setHandler:function(a){this.handlerMode=a;this.resetHandler()},resetHandler:function(){this.handler&&(this.handler.deactivate(),this.handler.destroy(),this.handler=null);"hover"==this.handlerMode?this.handler=new OpenLayers.Handler.Hover(this,{pause:this.handleEvent,move:this.reset},
2994 this.handlerOptions):"click"==this.handlerMode?this.handler=new OpenLayers.Handler.Click(this,{click:this.handleEvent},this.handlerOptions):"move"==this.handlerMode&&(this.handler=new OpenLayers.Handler.Hover(this,{pause:this.handleEvent,move:this.handleEvent},this.handlerOptions));return this.handler?!0:!1},initialize:function(a){a=a||{};a.handlerOptions=a.handlerOptions||this.defaultHandlerOptions;OpenLayers.Control.prototype.initialize.apply(this,[a]);this.resetHandler()},handleEvent:function(a){if(null==
2995 a)this.reset();else{var b=this.map.getLonLatFromPixel(a.xy);if(b){var c=this.findLayers();if(0<c.length){for(var d={},e,f,g=0,h=c.length;g<h;g++)e=c[g],f=OpenLayers.Util.indexOf(this.map.layers,e),d[f]=e.getFeatureInfo(b);this.callback(d,b,a.xy)}}}},callback:function(){},reset:function(){this.callback(null)},findLayers:function(){for(var a=this.layers||this.map.layers,b=[],c,d=a.length-1;0<=d;--d)c=a[d],c instanceof OpenLayers.Layer.UTFGrid&&b.push(c);return b},CLASS_NAME:"OpenLayers.Control.UTFGrid"});OpenLayers.Format.CQL=function(){function a(a){function b(){var a=e.pop();switch(a.type){case "LOGICAL":var c=b(),g=b();return new OpenLayers.Filter.Logical({filters:[g,c],type:f[a.text.toUpperCase()]});case "NOT":return c=b(),new OpenLayers.Filter.Logical({filters:[c],type:OpenLayers.Filter.Logical.NOT});case "BETWEEN":return e.pop(),g=b(),a=b(),c=b(),new OpenLayers.Filter.Comparison({property:c,lowerBoundary:a,upperBoundary:g,type:OpenLayers.Filter.Comparison.BETWEEN});case "COMPARISON":return g=
2996 b(),c=b(),new OpenLayers.Filter.Comparison({property:c,value:g,type:d[a.text.toUpperCase()]});case "VALUE":return/^'.*'$/.test(a.text)?a.text.substr(1,a.text.length-2):Number(a.text);case "SPATIAL":switch(a.text.toUpperCase()){case "BBOX":var c=b(),a=b(),g=b(),h=b(),i=b();return new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.BBOX,property:i,value:OpenLayers.Bounds.fromArray([h,g,a,c])});case "INTERSECTS":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.INTERSECTS,
2997 property:c,value:g});case "WITHIN":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.WITHIN,property:c,value:g});case "CONTAINS":return g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.CONTAINS,property:c,value:g});case "DWITHIN":return a=b(),g=b(),c=b(),new OpenLayers.Filter.Spatial({type:OpenLayers.Filter.Spatial.DWITHIN,value:g,property:c,distance:Number(a)})}case "GEOMETRY":return OpenLayers.Geometry.fromWKT(a.text);default:return a.text}}
2998 for(var c=[],e=[];a.length;){var g=a.shift();switch(g.type){case "PROPERTY":case "GEOMETRY":case "VALUE":e.push(g);break;case "COMPARISON":case "BETWEEN":case "LOGICAL":for(var i=h[g.type];0<c.length&&h[c[c.length-1].type]<=i;)e.push(c.pop());c.push(g);break;case "SPATIAL":case "NOT":case "LPAREN":c.push(g);break;case "RPAREN":for(;0<c.length&&"LPAREN"!=c[c.length-1].type;)e.push(c.pop());c.pop();0<c.length&&"SPATIAL"==c[c.length-1].type&&e.push(c.pop());case "COMMA":case "END":break;default:throw Error("Unknown token type "+
2999 g.type);}}for(;0<c.length;)e.push(c.pop());a=b();if(0<e.length){a="Remaining tokens after building AST: \n";for(c=e.length-1;0<=c;c--)a+=e[c].type+": "+e[c].text+"\n";throw Error(a);}return a}var b={PROPERTY:/^[_a-zA-Z]\w*/,COMPARISON:/^(=|<>|<=|<|>=|>|LIKE)/i,COMMA:/^,/,LOGICAL:/^(AND|OR)/i,VALUE:/^('\w+'|\d+(\.\d*)?|\.\d+)/,LPAREN:/^\(/,RPAREN:/^\)/,SPATIAL:/^(BBOX|INTERSECTS|DWITHIN|WITHIN|CONTAINS)/i,NOT:/^NOT/i,BETWEEN:/^BETWEEN/i,GEOMETRY:function(a){var b=/^(POINT|LINESTRING|POLYGON|MULTIPOINT|MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)/.exec(a);
3000 if(b){var c=a.length,b=a.indexOf("(",b[0].length);if(-1<b)for(var d=1;b<c&&0<d;)switch(b++,a.charAt(b)){case "(":d++;break;case ")":d--}return[a.substr(0,b+1)]}},END:/^$/},c={LPAREN:["GEOMETRY","SPATIAL","PROPERTY","VALUE","LPAREN"],RPAREN:["NOT","LOGICAL","END","RPAREN"],PROPERTY:["COMPARISON","BETWEEN","COMMA"],BETWEEN:["VALUE"],COMPARISON:["VALUE"],COMMA:["GEOMETRY","VALUE","PROPERTY"],VALUE:["LOGICAL","COMMA","RPAREN","END"],SPATIAL:["LPAREN"],LOGICAL:["NOT","VALUE","SPATIAL","PROPERTY","LPAREN"],
3001 NOT:["PROPERTY","LPAREN"],GEOMETRY:["COMMA","RPAREN"]},d={"=":OpenLayers.Filter.Comparison.EQUAL_TO,"<>":OpenLayers.Filter.Comparison.NOT_EQUAL_TO,"<":OpenLayers.Filter.Comparison.LESS_THAN,"<=":OpenLayers.Filter.Comparison.LESS_THAN_OR_EQUAL_TO,">":OpenLayers.Filter.Comparison.GREATER_THAN,">=":OpenLayers.Filter.Comparison.GREATER_THAN_OR_EQUAL_TO,LIKE:OpenLayers.Filter.Comparison.LIKE,BETWEEN:OpenLayers.Filter.Comparison.BETWEEN},e={},f={AND:OpenLayers.Filter.Logical.AND,OR:OpenLayers.Filter.Logical.OR},
3002 g={},h={RPAREN:3,LOGICAL:2,COMPARISON:1},i;for(i in d)d.hasOwnProperty(i)&&(e[d[i]]=i);for(i in f)f.hasOwnProperty(i)&&(g[f[i]]=i);return OpenLayers.Class(OpenLayers.Format,{read:function(d){var e=d,d=[],f,g=["NOT","GEOMETRY","SPATIAL","PROPERTY","LPAREN"];do{a:{f=g;for(var h=void 0,g=void 0,i=f.length,h=0;h<i;h++){var g=f[h],p=b[g]instanceof RegExp?b[g].exec(e):(0,b[g])(e);if(p){f=p[0];e=e.substr(f.length).replace(/^\s*/,"");f={type:g,text:f,remainder:e};break a}}d="ERROR: In parsing: ["+e+"], expected one of: ";
3003 for(h=0;h<i;h++)g=f[h],d+="\n "+g+": "+b[g];throw Error(d);}e=f.remainder;g=c[f.type];if("END"!=f.type&&!g)throw Error("No follows list for "+f.type);d.push(f)}while("END"!=f.type);d=a(d);this.keepData&&(this.data=d);return d},write:function(a){if(a instanceof OpenLayers.Geometry)return a.toString();switch(a.CLASS_NAME){case "OpenLayers.Filter.Spatial":switch(a.type){case OpenLayers.Filter.Spatial.BBOX:return"BBOX("+a.property+","+a.value.toBBOX()+")";case OpenLayers.Filter.Spatial.DWITHIN:return"DWITHIN("+
3004 a.property+", "+this.write(a.value)+", "+a.distance+")";case OpenLayers.Filter.Spatial.WITHIN:return"WITHIN("+a.property+", "+this.write(a.value)+")";case OpenLayers.Filter.Spatial.INTERSECTS:return"INTERSECTS("+a.property+", "+this.write(a.value)+")";case OpenLayers.Filter.Spatial.CONTAINS:return"CONTAINS("+a.property+", "+this.write(a.value)+")";default:throw Error("Unknown spatial filter type: "+a.type);}case "OpenLayers.Filter.Logical":if(a.type==OpenLayers.Filter.Logical.NOT)return"NOT ("+this.write(a.filters[0])+
3005 ")";for(var b="(",c=!0,d=0;d<a.filters.length;d++)c?c=!1:b+=") "+g[a.type]+" (",b+=this.write(a.filters[d]);return b+")";case "OpenLayers.Filter.Comparison":return a.type==OpenLayers.Filter.Comparison.BETWEEN?a.property+" BETWEEN "+this.write(a.lowerBoundary)+" AND "+this.write(a.upperBoundary):a.property+" "+e[a.type]+" "+this.write(a.value);case void 0:if("string"===typeof a)return"'"+a+"'";if("number"===typeof a)return""+a;default:throw Error("Can't encode: "+a.CLASS_NAME+" "+a);}},CLASS_NAME:"OpenLayers.Format.CQL"})}();OpenLayers.Control.Split=OpenLayers.Class(OpenLayers.Control,{layer:null,source:null,sourceOptions:null,tolerance:null,edge:!0,deferDelete:!1,mutual:!0,targetFilter:null,sourceFilter:null,handler:null,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,[a]);this.options=a||{};this.options.source&&this.setSource(this.options.source)},setSource:function(a){this.active?(this.deactivate(),this.handler&&(this.handler.destroy(),delete this.handler),this.source=a,this.activate()):this.source=
3006 a},activate:function(){var a=OpenLayers.Control.prototype.activate.call(this);if(a)if(this.source){if(this.source.events)this.source.events.on({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this})}else this.handler||(this.handler=new OpenLayers.Handler.Path(this,{done:function(a){this.onSketchComplete({feature:new OpenLayers.Feature.Vector(a)})}},{layerOptions:this.sourceOptions})),this.handler.activate();return a},deactivate:function(){var a=OpenLayers.Control.prototype.deactivate.call(this);
3007 a&&this.source&&this.source.events&&this.layer.events.un({sketchcomplete:this.onSketchComplete,afterfeaturemodified:this.afterFeatureModified,scope:this});return a},onSketchComplete:function(a){this.feature=null;return!this.considerSplit(a.feature)},afterFeatureModified:function(a){a.modified&&"function"===typeof a.feature.geometry.split&&(this.feature=a.feature,this.considerSplit(a.feature))},removeByGeometry:function(a,b){for(var c=0,d=a.length;c<d;++c)if(a[c].geometry===b){a.splice(c,1);break}},
3008 isEligible:function(a){return a.geometry?a.state!==OpenLayers.State.DELETE&&"function"===typeof a.geometry.split&&this.feature!==a&&(!this.targetFilter||this.targetFilter.evaluate(a.attributes)):!1},considerSplit:function(a){var b=!1,c=!1;if(!this.sourceFilter||this.sourceFilter.evaluate(a.attributes)){for(var d=this.layer&&this.layer.features||[],e,f,g=[],h=[],i=this.layer===this.source&&this.mutual,j={edge:this.edge,tolerance:this.tolerance,mutual:i},k=[a.geometry],l,m,n,o=0,p=d.length;o<p;++o)if(l=
3009 d[o],this.isEligible(l)){m=[l.geometry];for(var q=0;q<k.length;++q){n=k[q];for(var r=0;r<m.length;++r)if(e=m[r],n.getBounds().intersectsBounds(e.getBounds())&&(e=n.split(e,j)))if(f=this.events.triggerEvent("beforesplit",{source:a,target:l}),!1!==f&&(i&&(f=e[0],1<f.length&&(f.unshift(q,1),Array.prototype.splice.apply(k,f),q+=f.length-3),e=e[1]),1<e.length))e.unshift(r,1),Array.prototype.splice.apply(m,e),r+=e.length-3}m&&1<m.length&&(this.geomsToFeatures(l,m),this.events.triggerEvent("split",{original:l,
3010 features:m}),Array.prototype.push.apply(g,m),h.push(l),c=!0)}k&&1<k.length&&(this.geomsToFeatures(a,k),this.events.triggerEvent("split",{original:a,features:k}),Array.prototype.push.apply(g,k),h.push(a),b=!0);if(b||c){if(this.deferDelete){d=[];o=0;for(p=h.length;o<p;++o)c=h[o],c.state===OpenLayers.State.INSERT?d.push(c):(c.state=OpenLayers.State.DELETE,this.layer.drawFeature(c));this.layer.destroyFeatures(d,{silent:!0});o=0;for(p=g.length;o<p;++o)g[o].state=OpenLayers.State.INSERT}else this.layer.destroyFeatures(h,
3011 {silent:!0});this.layer.addFeatures(g,{silent:!0});this.events.triggerEvent("aftersplit",{source:a,features:g})}}return b},geomsToFeatures:function(a,b){var c=a.clone();delete c.geometry;for(var d,e=0,f=b.length;e<f;++e)d=c.clone(),d.geometry=b[e],d.state=OpenLayers.State.INSERT,b[e]=d},destroy:function(){this.active&&this.deactivate();OpenLayers.Control.prototype.destroy.call(this)},CLASS_NAME:"OpenLayers.Control.Split"});OpenLayers.Layer.WMTS=OpenLayers.Class(OpenLayers.Layer.Grid,{isBaseLayer:!0,version:"1.0.0",requestEncoding:"KVP",url:null,layer:null,matrixSet:null,style:null,format:"image/jpeg",tileOrigin:null,tileFullExtent:null,formatSuffix:null,matrixIds:null,dimensions:null,params:null,zoomOffset:0,serverResolutions:null,formatSuffixMap:{"image/png":"png","image/png8":"png","image/png24":"png","image/png32":"png",png:"png","image/jpeg":"jpg","image/jpg":"jpg",jpeg:"jpg",jpg:"jpg"},matrix:null,initialize:function(a){var b=
3012 {url:!0,layer:!0,style:!0,matrixSet:!0},c;for(c in b)if(!(c in a))throw Error("Missing property '"+c+"' in layer configuration.");a.params=OpenLayers.Util.upperCaseObject(a.params);OpenLayers.Layer.Grid.prototype.initialize.apply(this,[a.name,a.url,a.params,a]);this.formatSuffix||(this.formatSuffix=this.formatSuffixMap[this.format]||this.format.split("/").pop());if(this.matrixIds&&(a=this.matrixIds.length)&&"string"===typeof this.matrixIds[0]){b=this.matrixIds;this.matrixIds=Array(a);for(c=0;c<a;++c)this.matrixIds[c]=
3013 {identifier:b[c]}}},setMap:function(){OpenLayers.Layer.Grid.prototype.setMap.apply(this,arguments);this.updateMatrixProperties()},updateMatrixProperties:function(){if(this.matrix=this.getMatrix())if(this.matrix.topLeftCorner&&(this.tileOrigin=this.matrix.topLeftCorner),this.matrix.tileWidth&&this.matrix.tileHeight&&(this.tileSize=new OpenLayers.Size(this.matrix.tileWidth,this.matrix.tileHeight)),this.tileOrigin||(this.tileOrigin=new OpenLayers.LonLat(this.maxExtent.left,this.maxExtent.top)),!this.tileFullExtent)this.tileFullExtent=
3014 this.maxExtent},moveTo:function(a,b,c){(b||!this.matrix)&&this.updateMatrixProperties();return OpenLayers.Layer.Grid.prototype.moveTo.apply(this,arguments)},clone:function(a){null==a&&(a=new OpenLayers.Layer.WMTS(this.options));return a=OpenLayers.Layer.Grid.prototype.clone.apply(this,[a])},getIdentifier:function(){return this.getServerZoom()},getMatrix:function(){var a;if(!this.matrixIds||0===this.matrixIds.length)a={identifier:this.getIdentifier()};else if("scaleDenominator"in this.matrixIds[0])for(var b=
3015 OpenLayers.METERS_PER_INCH*OpenLayers.INCHES_PER_UNIT[this.units]*this.getServerResolution()/2.8E-4,c=Number.POSITIVE_INFINITY,d,e=0,f=this.matrixIds.length;e<f;++e)d=Math.abs(1-this.matrixIds[e].scaleDenominator/b),d<c&&(c=d,a=this.matrixIds[e]);else a=this.matrixIds[this.getIdentifier()];return a},getTileInfo:function(a){var b=this.getServerResolution(),c=(a.lon-this.tileOrigin.lon)/(b*this.tileSize.w),a=(this.tileOrigin.lat-a.lat)/(b*this.tileSize.h),b=Math.floor(c),d=Math.floor(a);return{col:b,
3016 row:d,i:Math.floor((c-b)*this.tileSize.w),j:Math.floor((a-d)*this.tileSize.h)}},getURL:function(a){var a=this.adjustBounds(a),b="";if(!this.tileFullExtent||this.tileFullExtent.intersectsBounds(a)){var c=this.getTileInfo(a.getCenterLonLat()),a=this.dimensions;if("REST"===this.requestEncoding.toUpperCase())if(b=this.params,"string"===typeof this.url&&-1!==this.url.indexOf("{")){var d=this.url.replace(/\{/g,"${"),c={style:this.style,Style:this.style,TileMatrixSet:this.matrixSet,TileMatrix:this.matrix.identifier,
3017 TileRow:c.row,TileCol:c.col};if(a){var e,f;for(f=a.length-1;0<=f;--f)e=a[f],c[e]=b[e.toUpperCase()]}b=OpenLayers.String.format(d,c)}else{d=this.version+"/"+this.layer+"/"+this.style+"/";if(a)for(f=0;f<a.length;f++)b[a[f]]&&(d=d+b[a[f]]+"/");d=d+this.matrixSet+"/"+this.matrix.identifier+"/"+c.row+"/"+c.col+"."+this.formatSuffix;b=OpenLayers.Util.isArray(this.url)?this.selectUrl(d,this.url):this.url;b.match(/\/$/)||(b+="/");b+=d}else"KVP"===this.requestEncoding.toUpperCase()&&(b={SERVICE:"WMTS",REQUEST:"GetTile",
3018 VERSION:this.version,LAYER:this.layer,STYLE:this.style,TILEMATRIXSET:this.matrixSet,TILEMATRIX:this.matrix.identifier,TILEROW:c.row,TILECOL:c.col,FORMAT:this.format},b=OpenLayers.Layer.Grid.prototype.getFullRequestString.apply(this,[b]))}return b},mergeNewParams:function(a){if("KVP"===this.requestEncoding.toUpperCase())return OpenLayers.Layer.Grid.prototype.mergeNewParams.apply(this,[OpenLayers.Util.upperCaseObject(a)])},CLASS_NAME:"OpenLayers.Layer.WMTS"});OpenLayers.Protocol.SOS.v1_0_0=OpenLayers.Class(OpenLayers.Protocol,{fois:null,formatOptions:null,initialize:function(a){OpenLayers.Protocol.prototype.initialize.apply(this,[a]);a.format||(this.format=new OpenLayers.Format.SOSGetFeatureOfInterest(this.formatOptions))},destroy:function(){this.options&&!this.options.format&&this.format.destroy();this.format=null;OpenLayers.Protocol.prototype.destroy.apply(this)},read:function(a){a=OpenLayers.Util.extend({},a);OpenLayers.Util.applyDefaults(a,this.options||
3019 {});var b=new OpenLayers.Protocol.Response({requestType:"read"}),c=this.format,c=OpenLayers.Format.XML.prototype.write.apply(c,[c.writeNode("sos:GetFeatureOfInterest",{fois:this.fois})]);b.priv=OpenLayers.Request.POST({url:a.url,callback:this.createCallback(this.handleRead,b,a),data:c});return b},handleRead:function(a,b){if(b.callback){var c=a.priv;200<=c.status&&300>c.status?(a.features=this.parseFeatures(c),a.code=OpenLayers.Protocol.Response.SUCCESS):a.code=OpenLayers.Protocol.Response.FAILURE;
3020 b.callback.call(b.scope,a)}},parseFeatures:function(a){var b=a.responseXML;if(!b||!b.documentElement)b=a.responseText;return!b||0>=b.length?null:this.format.read(b)},CLASS_NAME:"OpenLayers.Protocol.SOS.v1_0_0"});OpenLayers.Layer.KaMapCache=OpenLayers.Class(OpenLayers.Layer.KaMap,{IMAGE_EXTENSIONS:{jpeg:"jpg",gif:"gif",png:"png",png8:"png",png24:"png",dithered:"png"},DEFAULT_FORMAT:"jpeg",initialize:function(a,b,c,d){OpenLayers.Layer.KaMap.prototype.initialize.apply(this,arguments);this.extension=this.IMAGE_EXTENSIONS[this.params.i.toLowerCase()||this.DEFAULT_FORMAT]},getURL:function(a){var a=this.adjustBounds(a),b=this.map.getResolution(),c=Math.round(1E4*this.map.getScale())/1E4,d=Math.round(a.left/b),a=
3021 -Math.round(a.top/b),b=Math.floor(d/this.tileSize.w/this.params.metaTileSize.w)*this.tileSize.w*this.params.metaTileSize.w,e=Math.floor(a/this.tileSize.h/this.params.metaTileSize.h)*this.tileSize.h*this.params.metaTileSize.h,c=["/",this.params.map,"/",c,"/",this.params.g.replace(/\s/g,"_"),"/def/t",e,"/l",b,"/t",a,"l",d,".",this.extension],d=this.url;OpenLayers.Util.isArray(d)&&(d=this.selectUrl(c.join(""),d));return d+c.join("")},CLASS_NAME:"OpenLayers.Layer.KaMapCache"});OpenLayers.Protocol.WFS.v1_1_0=OpenLayers.Class(OpenLayers.Protocol.WFS.v1,{version:"1.1.0",initialize:function(a){OpenLayers.Protocol.WFS.v1.prototype.initialize.apply(this,arguments);this.outputFormat&&!this.readFormat&&("gml2"==this.outputFormat.toLowerCase()?this.readFormat=new OpenLayers.Format.GML.v2({featureType:this.featureType,featureNS:this.featureNS,geometryName:this.geometryName}):"json"==this.outputFormat.toLowerCase()&&(this.readFormat=new OpenLayers.Format.GeoJSON))},CLASS_NAME:"OpenLayers.Protocol.WFS.v1_1_0"});OpenLayers.Format.WMSCapabilities.v1_1_1=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.1",readers:{wms:OpenLayers.Util.applyDefaults({SRS:function(a,b){b.srs[this.getChildValue(a)]=!0}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1"});OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1_1,{version:"1.1.1",profile:"WMSC",readers:{wms:OpenLayers.Util.applyDefaults({VendorSpecificCapabilities:function(a,b){b.vendorSpecific={tileSets:[]};this.readChildNodes(a,b.vendorSpecific)},TileSet:function(a,b){var c={srs:{},bbox:{},resolutions:[]};this.readChildNodes(a,c);b.tileSets.push(c)},Resolutions:function(a,b){for(var c=this.getChildValue(a).split(" "),d=0,e=c.length;d<e;d++)""!=c[d]&&b.resolutions.push(parseFloat(c[d]))},
3022 Width:function(a,b){b.width=parseInt(this.getChildValue(a))},Height:function(a,b){b.height=parseInt(this.getChildValue(a))},Layers:function(a,b){b.layers=this.getChildValue(a)},Styles:function(a,b){b.styles=this.getChildValue(a)}},OpenLayers.Format.WMSCapabilities.v1_1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_1_WMSC"});OpenLayers.Format.WMSCapabilities.v1_1_0=OpenLayers.Class(OpenLayers.Format.WMSCapabilities.v1_1,{version:"1.1.0",readers:{wms:OpenLayers.Util.applyDefaults({SRS:function(a,b){for(var c=this.getChildValue(a).split(/ +/),d=0,e=c.length;d<e;d++)b.srs[c[d]]=!0}},OpenLayers.Format.WMSCapabilities.v1_1.prototype.readers.wms)},CLASS_NAME:"OpenLayers.Format.WMSCapabilities.v1_1_0"});OpenLayers.Control.LayerSwitcher=OpenLayers.Class(OpenLayers.Control,{roundedCorner:!1,roundedCornerColor:"darkblue",layerStates:null,layersDiv:null,baseLayersDiv:null,baseLayers:null,dataLbl:null,dataLayersDiv:null,dataLayers:null,minimizeDiv:null,maximizeDiv:null,ascending:!0,initialize:function(a){OpenLayers.Control.prototype.initialize.apply(this,arguments);this.layerStates=[];this.roundedCorner&&OpenLayers.Console.warn("roundedCorner option is deprecated")},destroy:function(){this.clearLayersArray("base");
3023 this.clearLayersArray("data");this.map.events.un({buttonclick:this.onButtonClick,addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,scope:this});this.events.unregister("buttonclick",this,this.onButtonClick);OpenLayers.Control.prototype.destroy.apply(this,arguments)},setMap:function(a){OpenLayers.Control.prototype.setMap.apply(this,arguments);this.map.events.on({addlayer:this.redraw,changelayer:this.redraw,removelayer:this.redraw,changebaselayer:this.redraw,
3024 scope:this});this.outsideViewport?(this.events.attachToElement(this.div),this.events.register("buttonclick",this,this.onButtonClick)):this.map.events.register("buttonclick",this,this.onButtonClick)},draw:function(){OpenLayers.Control.prototype.draw.apply(this);this.loadContents();this.outsideViewport||this.minimizeControl();this.redraw();return this.div},onButtonClick:function(a){a=a.buttonElement;a===this.minimizeDiv?this.minimizeControl():a===this.maximizeDiv?this.maximizeControl():a._layerSwitcher===
3025 this.id&&(a["for"]&&(a=document.getElementById(a["for"])),a.disabled||("radio"==a.type?(a.checked=!0,this.map.setBaseLayer(this.map.getLayer(a._layer))):(a.checked=!a.checked,this.updateMap())))},clearLayersArray:function(a){this[a+"LayersDiv"].innerHTML="";this[a+"Layers"]=[]},checkRedraw:function(){var a=!1;if(!this.layerStates.length||this.map.layers.length!=this.layerStates.length)a=!0;else for(var b=0,c=this.layerStates.length;b<c;b++){var d=this.layerStates[b],e=this.map.layers[b];if(d.name!=
3026 e.name||d.inRange!=e.inRange||d.id!=e.id||d.visibility!=e.visibility){a=!0;break}}return a},redraw:function(){if(!this.checkRedraw())return this.div;this.clearLayersArray("base");this.clearLayersArray("data");var a=!1,b=!1,c=this.map.layers.length;this.layerStates=Array(c);for(var d=0;d<c;d++){var e=this.map.layers[d];this.layerStates[d]={name:e.name,visibility:e.visibility,inRange:e.inRange,id:e.id}}var f=this.map.layers.slice();this.ascending||f.reverse();d=0;for(c=f.length;d<c;d++){var e=f[d],
3027 g=e.isBaseLayer;if(e.displayInLayerSwitcher){g?b=!0:a=!0;var h=g?e==this.map.baseLayer:e.getVisibility(),i=document.createElement("input");i.id=this.id+"_input_"+e.name;i.name=g?this.id+"_baseLayers":e.name;i.type=g?"radio":"checkbox";i.value=e.name;i.checked=h;i.defaultChecked=h;i.className="olButton";i._layer=e.id;i._layerSwitcher=this.id;!g&&!e.inRange&&(i.disabled=!0);h=document.createElement("label");h["for"]=i.id;OpenLayers.Element.addClass(h,"labelSpan olButton");h._layer=e.id;h._layerSwitcher=
3028 this.id;!g&&!e.inRange&&(h.style.color="gray");h.innerHTML=e.name;h.style.verticalAlign=g?"bottom":"baseline";var j=document.createElement("br");(g?this.baseLayers:this.dataLayers).push({layer:e,inputElem:i,labelSpan:h});e=g?this.baseLayersDiv:this.dataLayersDiv;e.appendChild(i);e.appendChild(h);e.appendChild(j)}}this.dataLbl.style.display=a?"":"none";this.baseLbl.style.display=b?"":"none";return this.div},updateMap:function(){for(var a=0,b=this.baseLayers.length;a<b;a++){var c=this.baseLayers[a];
3029 c.inputElem.checked&&this.map.setBaseLayer(c.layer,!1)}a=0;for(b=this.dataLayers.length;a<b;a++)c=this.dataLayers[a],c.layer.setVisibility(c.inputElem.checked)},maximizeControl:function(a){this.div.style.width="";this.div.style.height="";this.showControls(!1);null!=a&&OpenLayers.Event.stop(a)},minimizeControl:function(a){this.div.style.width="0px";this.div.style.height="0px";this.showControls(!0);null!=a&&OpenLayers.Event.stop(a)},showControls:function(a){this.maximizeDiv.style.display=a?"":"none";
3030 this.minimizeDiv.style.display=a?"none":"";this.layersDiv.style.display=a?"none":""},loadContents:function(){this.layersDiv=document.createElement("div");this.layersDiv.id=this.id+"_layersDiv";OpenLayers.Element.addClass(this.layersDiv,"layersDiv");this.baseLbl=document.createElement("div");this.baseLbl.innerHTML=OpenLayers.i18n("Base Layer");OpenLayers.Element.addClass(this.baseLbl,"baseLbl");this.baseLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.baseLayersDiv,"baseLayersDiv");
3031 this.dataLbl=document.createElement("div");this.dataLbl.innerHTML=OpenLayers.i18n("Overlays");OpenLayers.Element.addClass(this.dataLbl,"dataLbl");this.dataLayersDiv=document.createElement("div");OpenLayers.Element.addClass(this.dataLayersDiv,"dataLayersDiv");this.ascending?(this.layersDiv.appendChild(this.baseLbl),this.layersDiv.appendChild(this.baseLayersDiv),this.layersDiv.appendChild(this.dataLbl),this.layersDiv.appendChild(this.dataLayersDiv)):(this.layersDiv.appendChild(this.dataLbl),this.layersDiv.appendChild(this.dataLayersDiv),
3032 this.layersDiv.appendChild(this.baseLbl),this.layersDiv.appendChild(this.baseLayersDiv));this.div.appendChild(this.layersDiv);this.roundedCorner&&(OpenLayers.Rico.Corner.round(this.div,{corners:"tl bl",bgColor:"transparent",color:this.roundedCornerColor,blend:!1}),OpenLayers.Rico.Corner.changeOpacity(this.layersDiv,0.75));var a=OpenLayers.Util.getImageLocation("layer-switcher-maximize.png");this.maximizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MaximizeDiv",null,null,a,"absolute");
3033 OpenLayers.Element.addClass(this.maximizeDiv,"maximizeDiv olButton");this.maximizeDiv.style.display="none";this.div.appendChild(this.maximizeDiv);a=OpenLayers.Util.getImageLocation("layer-switcher-minimize.png");this.minimizeDiv=OpenLayers.Util.createAlphaImageDiv("OpenLayers_Control_MinimizeDiv",null,null,a,"absolute");OpenLayers.Element.addClass(this.minimizeDiv,"minimizeDiv olButton");this.minimizeDiv.style.display="none";this.div.appendChild(this.minimizeDiv)},CLASS_NAME:"OpenLayers.Control.LayerSwitcher"});OpenLayers.Format.Atom=OpenLayers.Class(OpenLayers.Format.XML,{namespaces:{atom:"http://www.w3.org/2005/Atom",georss:"http://www.georss.org/georss"},feedTitle:"untitled",defaultEntryTitle:"untitled",gmlParser:null,xy:!1,read:function(a){"string"==typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));return this.parseFeatures(a)},write:function(a){var b;if(OpenLayers.Util.isArray(a)){b=this.createElementNSPlus("atom:feed");b.appendChild(this.createElementNSPlus("atom:title",{value:this.feedTitle}));
3034 for(var c=0,d=a.length;c<d;c++)b.appendChild(this.buildEntryNode(a[c]))}else b=this.buildEntryNode(a);return OpenLayers.Format.XML.prototype.write.apply(this,[b])},buildContentNode:function(a){var b=this.createElementNSPlus("atom:content",{attributes:{type:a.type||null}});if(a.src)b.setAttribute("src",a.src);else if("text"==a.type||null==a.type)b.appendChild(this.createTextNode(a.value));else if("html"==a.type){if("string"!=typeof a.value)throw"HTML content must be in form of an escaped string";b.appendChild(this.createTextNode(a.value))}else"xhtml"==
3035 a.type?b.appendChild(a.value):"xhtml"==a.type||a.type.match(/(\+|\/)xml$/)?b.appendChild(a.value):b.appendChild(this.createTextNode(a.value));return b},buildEntryNode:function(a){var b=a.attributes,c=b.atom||{},d=this.createElementNSPlus("atom:entry");if(c.authors)for(var e=OpenLayers.Util.isArray(c.authors)?c.authors:[c.authors],f=0,g=e.length;f<g;f++)d.appendChild(this.buildPersonConstructNode("author",e[f]));if(c.categories)for(var e=OpenLayers.Util.isArray(c.categories)?c.categories:[c.categories],
3036 h,f=0,g=e.length;f<g;f++)h=e[f],d.appendChild(this.createElementNSPlus("atom:category",{attributes:{term:h.term,scheme:h.scheme||null,label:h.label||null}}));c.content&&d.appendChild(this.buildContentNode(c.content));if(c.contributors){e=OpenLayers.Util.isArray(c.contributors)?c.contributors:[c.contributors];f=0;for(g=e.length;f<g;f++)d.appendChild(this.buildPersonConstructNode("contributor",e[f]))}a.fid&&d.appendChild(this.createElementNSPlus("atom:id",{value:a.fid}));if(c.links){e=OpenLayers.Util.isArray(c.links)?
3037 c.links:[c.links];f=0;for(g=e.length;f<g;f++)h=e[f],d.appendChild(this.createElementNSPlus("atom:link",{attributes:{href:h.href,rel:h.rel||null,type:h.type||null,hreflang:h.hreflang||null,title:h.title||null,length:h.length||null}}))}c.published&&d.appendChild(this.createElementNSPlus("atom:published",{value:c.published}));c.rights&&d.appendChild(this.createElementNSPlus("atom:rights",{value:c.rights}));if(c.summary||b.description)d.appendChild(this.createElementNSPlus("atom:summary",{value:c.summary||
3038 b.description}));d.appendChild(this.createElementNSPlus("atom:title",{value:c.title||b.title||this.defaultEntryTitle}));c.updated&&d.appendChild(this.createElementNSPlus("atom:updated",{value:c.updated}));a.geometry&&(b=this.createElementNSPlus("georss:where"),b.appendChild(this.buildGeometryNode(a.geometry)),d.appendChild(b));return d},initGmlParser:function(){this.gmlParser=new OpenLayers.Format.GML.v3({xy:this.xy,featureNS:"http://example.com#feature",internalProjection:this.internalProjection,
3039 externalProjection:this.externalProjection})},buildGeometryNode:function(a){this.gmlParser||this.initGmlParser();return this.gmlParser.writeNode("feature:_geometry",a).firstChild},buildPersonConstructNode:function(a,b){var c=["uri","email"],d=this.createElementNSPlus("atom:"+a);d.appendChild(this.createElementNSPlus("atom:name",{value:b.name}));for(var e=0,f=c.length;e<f;e++)b[c[e]]&&d.appendChild(this.createElementNSPlus("atom:"+c[e],{value:b[c[e]]}));return d},getFirstChildValue:function(a,b,c,
3040 d){return(a=this.getElementsByTagNameNS(a,b,c))&&0<a.length?this.getChildValue(a[0],d):d},parseFeature:function(a){var b={},c=null,d=null,e=null,f=this.namespaces.atom;this.parsePersonConstructs(a,"author",b);d=this.getElementsByTagNameNS(a,f,"category");0<d.length&&(b.categories=[]);for(var g=0,h=d.length;g<h;g++){c={};c.term=d[g].getAttribute("term");if(e=d[g].getAttribute("scheme"))c.scheme=e;if(e=d[g].getAttribute("label"))c.label=e;b.categories.push(c)}d=this.getElementsByTagNameNS(a,f,"content");
3041 if(0<d.length){c={};if(e=d[0].getAttribute("type"))c.type=e;(e=d[0].getAttribute("src"))?c.src=e:(c.value="text"==c.type||"html"==c.type||null==c.type?this.getFirstChildValue(a,f,"content",null):"xhtml"==c.type||c.type.match(/(\+|\/)xml$/)?this.getChildEl(d[0]):this.getFirstChildValue(a,f,"content",null),b.content=c)}this.parsePersonConstructs(a,"contributor",b);b.id=this.getFirstChildValue(a,f,"id",null);d=this.getElementsByTagNameNS(a,f,"link");0<d.length&&(b.links=Array(d.length));for(var i=["rel",
3042 "type","hreflang","title","length"],g=0,h=d.length;g<h;g++){c={};c.href=d[g].getAttribute("href");for(var j=0,k=i.length;j<k;j++)(e=d[g].getAttribute(i[j]))&&(c[i[j]]=e);b.links[g]=c}if(c=this.getFirstChildValue(a,f,"published",null))b.published=c;if(c=this.getFirstChildValue(a,f,"rights",null))b.rights=c;if(c=this.getFirstChildValue(a,f,"summary",null))b.summary=c;b.title=this.getFirstChildValue(a,f,"title",null);b.updated=this.getFirstChildValue(a,f,"updated",null);c={title:b.title,description:b.summary,
3043 atom:b};a=this.parseLocations(a)[0];a=new OpenLayers.Feature.Vector(a,c);a.fid=b.id;return a},parseFeatures:function(a){var b=[],c=this.getElementsByTagNameNS(a,this.namespaces.atom,"entry");0==c.length&&(c=[a]);for(var a=0,d=c.length;a<d;a++)b.push(this.parseFeature(c[a]));return b},parseLocations:function(a){var b=this.namespaces.georss,c={components:[]},d=this.getElementsByTagNameNS(a,b,"where");if(d&&0<d.length){this.gmlParser||this.initGmlParser();for(var e=0,f=d.length;e<f;e++)this.gmlParser.readChildNodes(d[e],
3044 c)}c=c.components;if((d=this.getElementsByTagNameNS(a,b,"point"))&&0<d.length){e=0;for(f=d.length;e<f;e++){var g=OpenLayers.String.trim(d[e].firstChild.nodeValue).split(/\s+/);2!=g.length&&(g=OpenLayers.String.trim(d[e].firstChild.nodeValue).split(/\s*,\s*/));c.push(new OpenLayers.Geometry.Point(g[1],g[0]))}}var h=this.getElementsByTagNameNS(a,b,"line");if(h&&0<h.length)for(var i,e=0,f=h.length;e<f;e++){d=OpenLayers.String.trim(h[e].firstChild.nodeValue).split(/\s+/);i=[];for(var j=0,k=d.length;j<
3045 k;j+=2)g=new OpenLayers.Geometry.Point(d[j+1],d[j]),i.push(g);c.push(new OpenLayers.Geometry.LineString(i))}if((a=this.getElementsByTagNameNS(a,b,"polygon"))&&0<a.length){e=0;for(f=a.length;e<f;e++){d=OpenLayers.String.trim(a[e].firstChild.nodeValue).split(/\s+/);i=[];j=0;for(k=d.length;j<k;j+=2)g=new OpenLayers.Geometry.Point(d[j+1],d[j]),i.push(g);c.push(new OpenLayers.Geometry.Polygon([new OpenLayers.Geometry.LinearRing(c)]))}}if(this.internalProjection&&this.externalProjection){e=0;for(f=c.length;e<
3046 f;e++)c[e]&&c[e].transform(this.externalProjection,this.internalProjection)}return c},parsePersonConstructs:function(a,b,c){for(var d=[],e=this.namespaces.atom,a=this.getElementsByTagNameNS(a,e,b),f=["uri","email"],g=0,h=a.length;g<h;g++){var i={};i.name=this.getFirstChildValue(a[g],e,"name",null);for(var j=0,k=f.length;j<k;j++){var l=this.getFirstChildValue(a[g],e,f[j],null);l&&(i[f[j]]=l)}d.push(i)}0<d.length&&(c[b+"s"]=d)},CLASS_NAME:"OpenLayers.Format.Atom"});OpenLayers.Control.KeyboardDefaults=OpenLayers.Class(OpenLayers.Control,{autoActivate:!0,slideFactor:75,observeElement:null,draw:function(){this.handler=new OpenLayers.Handler.Keyboard(this,{keydown:this.defaultKeyPress},{observeElement:this.observeElement||document})},defaultKeyPress:function(a){var b,c=!0;switch(a.keyCode){case OpenLayers.Event.KEY_LEFT:this.map.pan(-this.slideFactor,0);break;case OpenLayers.Event.KEY_RIGHT:this.map.pan(this.slideFactor,0);break;case OpenLayers.Event.KEY_UP:this.map.pan(0,
3047 -this.slideFactor);break;case OpenLayers.Event.KEY_DOWN:this.map.pan(0,this.slideFactor);break;case 33:b=this.map.getSize();this.map.pan(0,-0.75*b.h);break;case 34:b=this.map.getSize();this.map.pan(0,0.75*b.h);break;case 35:b=this.map.getSize();this.map.pan(0.75*b.w,0);break;case 36:b=this.map.getSize();this.map.pan(-0.75*b.w,0);break;case 43:case 61:case 187:case 107:this.map.zoomIn();break;case 45:case 109:case 189:case 95:this.map.zoomOut();break;default:c=!1}c&&OpenLayers.Event.stop(a)},CLASS_NAME:"OpenLayers.Control.KeyboardDefaults"});OpenLayers.Format.WMTSCapabilities.v1_0_0=OpenLayers.Class(OpenLayers.Format.OWSCommon.v1_1_0,{version:"1.0.0",namespaces:{ows:"http://www.opengis.net/ows/1.1",wmts:"http://www.opengis.net/wmts/1.0",xlink:"http://www.w3.org/1999/xlink"},yx:null,defaultPrefix:"wmts",initialize:function(a){OpenLayers.Format.XML.prototype.initialize.apply(this,[a]);this.options=a;a=OpenLayers.Util.extend({},OpenLayers.Format.WMTSCapabilities.prototype.yx);this.yx=OpenLayers.Util.extend(a,this.yx)},read:function(a){"string"==
3048 typeof a&&(a=OpenLayers.Format.XML.prototype.read.apply(this,[a]));a&&9==a.nodeType&&(a=a.documentElement);var b={};this.readNode(a,b);b.version=this.version;return b},readers:{wmts:{Capabilities:function(a,b){this.readChildNodes(a,b)},Contents:function(a,b){b.contents={};b.contents.layers=[];b.contents.tileMatrixSets={};this.readChildNodes(a,b.contents)},Layer:function(a,b){var c={styles:[],formats:[],dimensions:[],tileMatrixSetLinks:[],layers:[]};this.readChildNodes(a,c);b.layers.push(c)},Style:function(a,
3049 b){var c={};c.isDefault="true"===a.getAttribute("isDefault");this.readChildNodes(a,c);b.styles.push(c)},Format:function(a,b){b.formats.push(this.getChildValue(a))},TileMatrixSetLink:function(a,b){var c={};this.readChildNodes(a,c);b.tileMatrixSetLinks.push(c)},TileMatrixSet:function(a,b){if(b.layers){var c={matrixIds:[]};this.readChildNodes(a,c);b.tileMatrixSets[c.identifier]=c}else b.tileMatrixSet=this.getChildValue(a)},TileMatrix:function(a,b){var c={supportedCRS:b.supportedCRS};this.readChildNodes(a,
3050 c);b.matrixIds.push(c)},ScaleDenominator:function(a,b){b.scaleDenominator=parseFloat(this.getChildValue(a))},TopLeftCorner:function(a,b){var c=this.getChildValue(a).split(" "),d;b.supportedCRS&&(d=!!this.yx[b.supportedCRS.replace(/urn:ogc:def:crs:(\w+):.+:(\w+)$/,"urn:ogc:def:crs:$1::$2")]);b.topLeftCorner=d?new OpenLayers.LonLat(c[1],c[0]):new OpenLayers.LonLat(c[0],c[1])},TileWidth:function(a,b){b.tileWidth=parseInt(this.getChildValue(a))},TileHeight:function(a,b){b.tileHeight=parseInt(this.getChildValue(a))},
3051 MatrixWidth:function(a,b){b.matrixWidth=parseInt(this.getChildValue(a))},MatrixHeight:function(a,b){b.matrixHeight=parseInt(this.getChildValue(a))},ResourceURL:function(a,b){b.resourceUrl=b.resourceUrl||{};b.resourceUrl[a.getAttribute("resourceType")]={format:a.getAttribute("format"),template:a.getAttribute("template")}},WSDL:function(a,b){b.wsdl={};b.wsdl.href=a.getAttribute("xlink:href")},ServiceMetadataURL:function(a,b){b.serviceMetadataUrl={};b.serviceMetadataUrl.href=a.getAttribute("xlink:href")},
3052 LegendURL:function(a,b){b.legend={};b.legend.href=a.getAttribute("xlink:href");b.legend.format=a.getAttribute("format")},Dimension:function(a,b){var c={values:[]};this.readChildNodes(a,c);b.dimensions.push(c)},Default:function(a,b){b["default"]=this.getChildValue(a)},Value:function(a,b){b.values.push(this.getChildValue(a))}},ows:OpenLayers.Format.OWSCommon.v1_1_0.prototype.readers.ows},CLASS_NAME:"OpenLayers.Format.WMTSCapabilities.v1_0_0"});
3053 (function(h){h.deparam=function(i,j){var d={},k={"true":!0,"false":!1,"null":null};h.each(i.replace(/\+/g," ").split("&"),function(i,l){var m;var a=l.split("="),c=decodeURIComponent(a[0]),g=d,f=0,b=c.split("]["),e=b.length-1;/\[/.test(b[0])&&/\]$/.test(b[e])?(b[e]=b[e].replace(/\]$/,""),b=b.shift().split("[").concat(b),e=b.length-1):e=0;if(2===a.length)if(a=decodeURIComponent(a[1]),j&&(a=a&&!isNaN(a)?+a:"undefined"===a?void 0:void 0!==k[a]?k[a]:a),e)for(;f<=e;f++)c=""===b[f]?g.length:b[f],m=g[c]=
3054 f<e?g[c]||(b[f+1]&&isNaN(b[f+1])?{}:[]):a,g=m;else h.isArray(d[c])?d[c].push(a):d[c]=void 0!==d[c]?[d[c],a]:a;else c&&(d[c]=j?void 0:"")});return d}})(jQuery);
3055 /*!
3056 *
3057 * jQuery Remember Plugin
3058 * Version 0.1.1
3059 *
3060 * Copyright Nick Dreckshage, licensed GPL & MIT
3061 * https://github.com/ndreckshage/jquery-remember
3062 *
3063 * A fork of jQuery Cookie Plugin
3064 * https://github.com/carhartl/jquery-cookie
3065 * Copyright Klaus Hartl
3066 * Released under the MIT licensed
3067 *
3068 */
3069
3070 (function($){
3071
3072 // recommend changing to return function(options) { if using require.js...
3073 $.remember = function(options){
3074 var settings,
3075 remember,
3076 controller;
3077
3078 settings = $.extend({
3079 name: null, // name/key of the cookie/localstorage item
3080 value: undefined, // value pair of cookie/localstorage
3081 getSet: false, // if true, will get if available, set if not. default is to just get OR set
3082 remove: false, // if true, will remove based on name/key
3083 use: 'default', // whether to use localstorage or cookies. default localstorage with cookie fallback.
3084 expires: null, // forces cookie (invalid localstorage attribue).
3085 path: null, // forces cookie.
3086 domain: null, // forces cookie.
3087 secure: null, // forces cookie.
3088 json: false, // will convert to json when set. parse with get.
3089 fallback: true, // whether to fallback to cookies if localstorage not available.
3090 raw: false, // if true, will skip uri encoding/decoding
3091 modernizr: false // set true if youd rather handle localstorage detection through modernizr
3092 }, options);
3093
3094 remember = {
3095 init: function(){
3096 var controller;
3097
3098 // controls what to do with the input. set - get - set/get - erase
3099 // set if name exists, value exists, and not set to remove cookie.
3100 // get if name exists, value does not exist, and not set to remove
3101 // remove if remove set to true
3102 if (settings.name !== null && settings.value !== undefined && settings.remove !== true){
3103 if (settings.getSet === true){
3104 var get = this.get();
3105 // if the value of get exists, return it. otherwise, set the value as specified.
3106 if (get === null){
3107 this.set();
3108 } else {
3109 controller = get;
3110 }
3111 } else {
3112 this.set();
3113 }
3114 } else if (settings.name !== null && settings.value === undefined && settings.remove !== true){
3115 controller = this.get();
3116 } else if (settings.name !== null && settings.remove === true){
3117 this.erase();
3118 }
3119
3120 // will return result of everything to calling js
3121 return controller;
3122 },
3123 get: function(){
3124 var use = this._use(),
3125 value = null,
3126 cookies,
3127 parts,
3128 name;
3129
3130 // grab the key value pair from localstorage
3131 if (use === 'localstorage') {
3132 value = localStorage.getItem(settings.name);
3133 }
3134
3135 // hit if cookie requested, and when double checking a get on an empty localstorage item
3136 if ((use === 'cookie') || (use === 'localstorage' && value === null && settings.fallback !== false)) {
3137
3138 // grab all the cookies from the browser, check if set, and loop through
3139 cookies = document.cookie ? document.cookie : null;
3140 if (cookies !== null){
3141 cookies = cookies.split(';');
3142 for (var i = 0; i < cookies.length; i++){
3143 // separate the key value pair
3144 parts = cookies[i].split('=');
3145 // set name and value to split parts, cleaning up whitespace
3146 name = parts.shift();
3147 name = settings.raw === false ? this._trim(this._decode(name)) : this._trim(name);
3148 value = parts[0];
3149 // break when we hit a match, or cookie is empty
3150 if (settings.name === name) {
3151 break;
3152 } else if (settings.fallback !== false) {
3153 value = localStorage.getItem(settings.name) || null;
3154 } else {
3155 value = null;
3156 }
3157 }
3158 }
3159 }
3160
3161 // decode uri and if json is requested, parse the cookie/localstorage and return to controller
3162 value = (value && settings.raw === false) ? this._decode(value) : value;
3163 value = (value && settings.json === true) ? JSON.parse(value) : value;
3164
3165 return value;
3166 },
3167 set: function(){
3168 var use = this._use();
3169
3170 // if set is hit, user has intentionally tried to set (get/set not hit)
3171 // clear the storage alternative, so the same value isnt stored in both
3172 this.erase();
3173
3174 // convert the value to store in json if requested
3175 settings.value = settings.json === true ? JSON.stringify(settings.value) : settings.value;
3176
3177 // encode
3178 settings.name = settings.raw === false ? encodeURIComponent(settings.name) : settings.name;
3179 settings.value = settings.raw === false ? encodeURIComponent(settings.value) : settings.value;
3180
3181 // store the key value pair in appropriate storage. set unless storage requirements failed
3182 if (use === 'localstorage'){
3183 localStorage.setItem(settings.name, settings.value);
3184 } else if (use !== false){
3185 // convert values that cant be stored and set
3186 settings.value = settings.value === null ? 'null' : settings.value;
3187 this._setCookie();
3188 }
3189 },
3190 erase: function(){
3191 var use = this._use();
3192
3193 // clear localstorage and cookies by setting expiration to negative
3194 if (use !== 'cookie' || settings.fallback !== false){
3195 localStorage.removeItem(settings.name);
3196 }
3197 if (use !== 'localstorage' || settings.fallback !== false){
3198 this._setCookie('', -1);
3199 }
3200 },
3201 _use: function(){
3202 var use,
3203 localStorageSupport = this._localStorage();
3204
3205 // if cookie requested, or any options set that only apply to cookies
3206 if (settings.use === 'cookie' || settings.expires !== null || settings.path !== null || settings.domain !== null || settings.secure !== null){
3207 use = 'cookie';
3208 } else {
3209 // use local storage if available
3210 if (localStorageSupport){
3211 use = 'localstorage';
3212 } else if (settings.fallback !== false) {
3213 // default to cookie, unless fallback banned
3214 use = 'cookie';
3215 } else {
3216 // if all this fails, nothing can be set
3217 use = false;
3218 }
3219 }
3220
3221 return use;
3222 },
3223 _setCookie: function(){
3224 // allow for varying parameters with defaults. value then expires as optional params
3225 var value = arguments.length > 0 ? arguments[0] : settings.value,
3226 expires = arguments.length > 1 ? arguments[1] : settings.expires,
3227 expire;
3228
3229 // set a date in the future (or negative to delete) based on expires date offset
3230 if (typeof expires === 'number') {
3231 expire = new Date();
3232 expire.setDate(expire.getDate() + expires);
3233 }
3234
3235 // set the cookies with all the varying settings
3236 document.cookie = [
3237 settings.name,
3238 '=',
3239 value,
3240 expire ? '; expires=' + expire.toUTCString() : '',
3241 settings.path ? '; path=' + settings.path : '',
3242 settings.domain ? '; domain=' + settings.domain : '',
3243 settings.secure ? '; secure' : ''
3244 ].join('');
3245 },
3246 _localStorage: function(){
3247 if (settings.modernizr === true && typeof Modernizr !== 'undefined'){
3248 return Modernizr.localstorage;
3249 } else {
3250 // check if a browser supports localstorage with simple try catch
3251 try {
3252 localStorage.setItem('jquery-remember-test','jquery-remember-test');
3253 localStorage.removeItem('jquery-remember-test');
3254 return true;
3255 } catch(e){
3256 return false;
3257 }
3258 }
3259 },
3260 _trim: function(s){
3261 // trail a strings leading/ending whitespace
3262 return s.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
3263 },
3264 _decode: function(s){
3265 return decodeURIComponent(s.replace(/\+/g, ' '));
3266 }
3267 };
3268
3269 return remember.init();
3270 };
3271
3272 return $.remember;
3273
3274 }(jQuery));
3275 (function(a){if(typeof define==="function"&&define.amd){if(typeof jQuery!=="undefined"){define(["jquery"],a)}else{define([],a)}}else{if(typeof jQuery!=="undefined"){a(jQuery)}else{a()}}})(function(b,e){var q={a:"href",img:"src",form:"action",base:"href",script:"src",iframe:"src",link:"href"},t=["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","fragment"],p={anchor:"fragment"},a={strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/},s=/^[0-9]+$/;function o(u,x){var z=decodeURI(u),w=a[x||false?"strict":"loose"].exec(z),y={attr:{},param:{},seg:{}},v=14;while(v--){y.attr[t[v]]=w[v]||""}y.param.query=f(y.attr.query);y.param.fragment=f(y.attr.fragment);y.seg.path=y.attr.path.replace(/^\/+|\/+$/g,"").split("/");y.seg.fragment=y.attr.fragment.replace(/^\/+|\/+$/g,"").split("/");y.attr.base=y.attr.host?(y.attr.protocol?y.attr.protocol+"://"+y.attr.host:y.attr.host)+(y.attr.port?":"+y.attr.port:""):"";return y}function m(v){var u=v.tagName;if(typeof u!=="undefined"){return q[u.toLowerCase()]}return u}function c(x,w){if(x[w].length===0){return x[w]={}}var v={};for(var u in x[w]){v[u]=x[w][u]}x[w]=v;return v}function l(y,w,v,z){var u=y.shift();if(!u){if(g(w[v])){w[v].push(z)}else{if("object"==typeof w[v]){w[v]=z}else{if("undefined"==typeof w[v]){w[v]=z}else{w[v]=[w[v],z]}}}}else{var x=w[v]=w[v]||[];if("]"==u){if(g(x)){if(""!=z){x.push(z)}}else{if("object"==typeof x){x[j(x).length]=z}else{x=w[v]=[w[v],z]}}}else{if(~u.indexOf("]")){u=u.substr(0,u.length-1);if(!s.test(u)&&g(x)){x=c(w,v)}l(y,x,u,z)}else{if(!s.test(u)&&g(x)){x=c(w,v)}l(y,x,u,z)}}}}function d(x,w,z){if(~w.indexOf("]")){var y=w.split("[");l(y,x,"base",z)}else{if(!s.test(w)&&g(x.base)){var v={};for(var u in x.base){v[u]=x.base[u]}x.base=v}i(x.base,w,z)}return x}function f(u){if(u==""){return{}}return h(String(u).split(/&|;/),function(v,A){try{A=decodeURIComponent(A.replace(/\+/g," "))}catch(x){}var B=A.indexOf("="),z=n(A),w=A.substr(0,z||B),y=A.substr(z||B,A.length),y=y.substr(y.indexOf("=")+1,y.length);if(""==w){w=A,y=""}return d(v,w,y)},{base:{}}).base}function i(x,w,y){var u=x[w];if(e===u){x[w]=y}else{if(g(u)){u.push(y)}else{x[w]=[u,y]}}}function n(x){var u=x.length,w,y;for(var v=0;v<u;++v){y=x[v];if("]"==y){w=false}if("["==y){w=true}if("="==y&&!w){return v}}}function h(y,v){var w=0,u=y.length>>0,x=arguments[2];while(w<u){if(w in y){x=v.call(e,x,y[w],w,y)}++w}return x}function g(u){return Object.prototype.toString.call(u)==="[object Array]"}function j(v){var u=[];for(prop in v){if(v.hasOwnProperty(prop)){u.push(prop)}}return u}function k(u){return Object(u)===u&&Object.getPrototypeOf(u)===Object.prototype}function r(u,v){if(arguments.length===1&&u===true){v=true;u=e}v=v||false;u=u||window.location.toString();return{data:o(u,v),attr:function(w){w=p[w]||w;return typeof w!=="undefined"?this.data.attr[w]:this.data.attr},param:function(x,w){if(k(x)){this.data.param.query=x;return this}else{if(w==e){return typeof x!=="undefined"?this.data.param.query[x]:this.data.param.query}else{this.data.param.query[x]=w;return this}}},removeParam:function(w){delete this.data.param.query[w]},fparam:function(w){return typeof w!=="undefined"?this.data.param.fragment[w]:this.data.param.fragment},segment:function(w){if(typeof w==="undefined"){return this.data.seg.path}else{w=w<0?this.data.seg.path.length+w:w-1;return this.data.seg.path[w]}},fsegment:function(w){if(typeof w==="undefined"){return this.data.seg.fragment}else{w=w<0?this.data.seg.fragment.length+w:w-1;return this.data.seg.fragment[w]}},toString:function(){var w="";if(this.data.attr.host!==""){w+=this.data.attr.protocol+"://"+this.data.attr.host}if(this.data.attr.port!=="80"){w+=":"+this.data.attr.port}w+=this.data.attr.path;Object.keys=Object.keys||function(C){var A=[];for(var B in C){if(C.hasOwnProperty(B)){A.push(B)}}return A};if(Object.keys(this.data.param.query).length>0){w+="?";var x=[];for(var y in this.data.param.query){x.push(encodeURIComponent(y)+"="+encodeURIComponent(this.data.param.query[y]))}w+=x.join("&")}if(Object.keys(this.data.param.fragment).length>0){w+="#";var z=[];for(var y in this.data.param.fragment){if(this.data.param.fragment[y]===""){z.push(y)}else{z.push(y+"="+this.data.param.fragment[y])}}w+=z.join("&")}return w}}}if(typeof b!=="undefined"){b.fn.url=function(v){var u="";if(this.length){u=b(this).attr(m(this[0]))||""}return r(u,v)};b.url=r}else{window.purl=r}});
3276 /*! jQuery UI - v1.10.3 - 2013-05-29
3277 * http://jqueryui.com
3278 * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js
3279 * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */
3280
3281 (function( $, undefined ) {
3282
3283 var uuid = 0,
3284 runiqueId = /^ui-id-\d+$/;
3285
3286 // $.ui might exist from components with no dependencies, e.g., $.ui.position
3287 $.ui = $.ui || {};
3288
3289 $.extend( $.ui, {
3290 version: "1.10.3",
3291
3292 keyCode: {
3293 BACKSPACE: 8,
3294 COMMA: 188,
3295 DELETE: 46,
3296 DOWN: 40,
3297 END: 35,
3298 ENTER: 13,
3299 ESCAPE: 27,
3300 HOME: 36,
3301 LEFT: 37,
3302 NUMPAD_ADD: 107,
3303 NUMPAD_DECIMAL: 110,
3304 NUMPAD_DIVIDE: 111,
3305 NUMPAD_ENTER: 108,
3306 NUMPAD_MULTIPLY: 106,
3307 NUMPAD_SUBTRACT: 109,
3308 PAGE_DOWN: 34,
3309 PAGE_UP: 33,
3310 PERIOD: 190,
3311 RIGHT: 39,
3312 SPACE: 32,
3313 TAB: 9,
3314 UP: 38
3315 }
3316 });
3317
3318 // plugins
3319 $.fn.extend({
3320 focus: (function( orig ) {
3321 return function( delay, fn ) {
3322 return typeof delay === "number" ?
3323 this.each(function() {
3324 var elem = this;
3325 setTimeout(function() {
3326 $( elem ).focus();
3327 if ( fn ) {
3328 fn.call( elem );
3329 }
3330 }, delay );
3331 }) :
3332 orig.apply( this, arguments );
3333 };
3334 })( $.fn.focus ),
3335
3336 scrollParent: function() {
3337 var scrollParent;
3338 if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
3339 scrollParent = this.parents().filter(function() {
3340 return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
3341 }).eq(0);
3342 } else {
3343 scrollParent = this.parents().filter(function() {
3344 return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
3345 }).eq(0);
3346 }
3347
3348 return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
3349 },
3350
3351 zIndex: function( zIndex ) {
3352 if ( zIndex !== undefined ) {
3353 return this.css( "zIndex", zIndex );
3354 }
3355
3356 if ( this.length ) {
3357 var elem = $( this[ 0 ] ), position, value;
3358 while ( elem.length && elem[ 0 ] !== document ) {
3359 // Ignore z-index if position is set to a value where z-index is ignored by the browser
3360 // This makes behavior of this function consistent across browsers
3361 // WebKit always returns auto if the element is positioned
3362 position = elem.css( "position" );
3363 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
3364 // IE returns 0 when zIndex is not specified
3365 // other browsers return a string
3366 // we ignore the case of nested elements with an explicit value of 0
3367 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
3368 value = parseInt( elem.css( "zIndex" ), 10 );
3369 if ( !isNaN( value ) && value !== 0 ) {
3370 return value;
3371 }
3372 }
3373 elem = elem.parent();
3374 }
3375 }
3376
3377 return 0;
3378 },
3379
3380 uniqueId: function() {
3381 return this.each(function() {
3382 if ( !this.id ) {
3383 this.id = "ui-id-" + (++uuid);
3384 }
3385 });
3386 },
3387
3388 removeUniqueId: function() {
3389 return this.each(function() {
3390 if ( runiqueId.test( this.id ) ) {
3391 $( this ).removeAttr( "id" );
3392 }
3393 });
3394 }
3395 });
3396
3397 // selectors
3398 function focusable( element, isTabIndexNotNaN ) {
3399 var map, mapName, img,
3400 nodeName = element.nodeName.toLowerCase();
3401 if ( "area" === nodeName ) {
3402 map = element.parentNode;
3403 mapName = map.name;
3404 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
3405 return false;
3406 }
3407 img = $( "img[usemap=#" + mapName + "]" )[0];
3408 return !!img && visible( img );
3409 }
3410 return ( /input|select|textarea|button|object/.test( nodeName ) ?
3411 !element.disabled :
3412 "a" === nodeName ?
3413 element.href || isTabIndexNotNaN :
3414 isTabIndexNotNaN) &&
3415 // the element and all of its ancestors must be visible
3416 visible( element );
3417 }
3418
3419 function visible( element ) {
3420 return $.expr.filters.visible( element ) &&
3421 !$( element ).parents().addBack().filter(function() {
3422 return $.css( this, "visibility" ) === "hidden";
3423 }).length;
3424 }
3425
3426 $.extend( $.expr[ ":" ], {
3427 data: $.expr.createPseudo ?
3428 $.expr.createPseudo(function( dataName ) {
3429 return function( elem ) {
3430 return !!$.data( elem, dataName );
3431 };
3432 }) :
3433 // support: jQuery <1.8
3434 function( elem, i, match ) {
3435 return !!$.data( elem, match[ 3 ] );
3436 },
3437
3438 focusable: function( element ) {
3439 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
3440 },
3441
3442 tabbable: function( element ) {
3443 var tabIndex = $.attr( element, "tabindex" ),
3444 isTabIndexNaN = isNaN( tabIndex );
3445 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
3446 }
3447 });
3448
3449 // support: jQuery <1.8
3450 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
3451 $.each( [ "Width", "Height" ], function( i, name ) {
3452 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
3453 type = name.toLowerCase(),
3454 orig = {
3455 innerWidth: $.fn.innerWidth,
3456 innerHeight: $.fn.innerHeight,
3457 outerWidth: $.fn.outerWidth,
3458 outerHeight: $.fn.outerHeight
3459 };
3460
3461 function reduce( elem, size, border, margin ) {
3462 $.each( side, function() {
3463 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
3464 if ( border ) {
3465 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
3466 }
3467 if ( margin ) {
3468 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
3469 }
3470 });
3471 return size;
3472 }
3473
3474 $.fn[ "inner" + name ] = function( size ) {
3475 if ( size === undefined ) {
3476 return orig[ "inner" + name ].call( this );
3477 }
3478
3479 return this.each(function() {
3480 $( this ).css( type, reduce( this, size ) + "px" );
3481 });
3482 };
3483
3484 $.fn[ "outer" + name] = function( size, margin ) {
3485 if ( typeof size !== "number" ) {
3486 return orig[ "outer" + name ].call( this, size );
3487 }
3488
3489 return this.each(function() {
3490 $( this).css( type, reduce( this, size, true, margin ) + "px" );
3491 });
3492 };
3493 });
3494 }
3495
3496 // support: jQuery <1.8
3497 if ( !$.fn.addBack ) {
3498 $.fn.addBack = function( selector ) {
3499 return this.add( selector == null ?
3500 this.prevObject : this.prevObject.filter( selector )
3501 );
3502 };
3503 }
3504
3505 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
3506 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
3507 $.fn.removeData = (function( removeData ) {
3508 return function( key ) {
3509 if ( arguments.length ) {
3510 return removeData.call( this, $.camelCase( key ) );
3511 } else {
3512 return removeData.call( this );
3513 }
3514 };
3515 })( $.fn.removeData );
3516 }
3517
3518
3519
3520
3521
3522 // deprecated
3523 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
3524
3525 $.support.selectstart = "onselectstart" in document.createElement( "div" );
3526 $.fn.extend({
3527 disableSelection: function() {
3528 return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
3529 ".ui-disableSelection", function( event ) {
3530 event.preventDefault();
3531 });
3532 },
3533
3534 enableSelection: function() {
3535 return this.unbind( ".ui-disableSelection" );
3536 }
3537 });
3538
3539 $.extend( $.ui, {
3540 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
3541 plugin: {
3542 add: function( module, option, set ) {
3543 var i,
3544 proto = $.ui[ module ].prototype;
3545 for ( i in set ) {
3546 proto.plugins[ i ] = proto.plugins[ i ] || [];
3547 proto.plugins[ i ].push( [ option, set[ i ] ] );
3548 }
3549 },
3550 call: function( instance, name, args ) {
3551 var i,
3552 set = instance.plugins[ name ];
3553 if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
3554 return;
3555 }
3556
3557 for ( i = 0; i < set.length; i++ ) {
3558 if ( instance.options[ set[ i ][ 0 ] ] ) {
3559 set[ i ][ 1 ].apply( instance.element, args );
3560 }
3561 }
3562 }
3563 },
3564
3565 // only used by resizable
3566 hasScroll: function( el, a ) {
3567
3568 //If overflow is hidden, the element might have extra content, but the user wants to hide it
3569 if ( $( el ).css( "overflow" ) === "hidden") {
3570 return false;
3571 }
3572
3573 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
3574 has = false;
3575
3576 if ( el[ scroll ] > 0 ) {
3577 return true;
3578 }
3579
3580 // TODO: determine which cases actually cause this to happen
3581 // if the element doesn't have the scroll set, see if it's possible to
3582 // set the scroll
3583 el[ scroll ] = 1;
3584 has = ( el[ scroll ] > 0 );
3585 el[ scroll ] = 0;
3586 return has;
3587 }
3588 });
3589
3590 })( jQuery );
3591 (function( $, undefined ) {
3592
3593 var uuid = 0,
3594 slice = Array.prototype.slice,
3595 _cleanData = $.cleanData;
3596 $.cleanData = function( elems ) {
3597 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
3598 try {
3599 $( elem ).triggerHandler( "remove" );
3600 // http://bugs.jquery.com/ticket/8235
3601 } catch( e ) {}
3602 }
3603 _cleanData( elems );
3604 };
3605
3606 $.widget = function( name, base, prototype ) {
3607 var fullName, existingConstructor, constructor, basePrototype,
3608 // proxiedPrototype allows the provided prototype to remain unmodified
3609 // so that it can be used as a mixin for multiple widgets (#8876)
3610 proxiedPrototype = {},
3611 namespace = name.split( "." )[ 0 ];
3612
3613 name = name.split( "." )[ 1 ];
3614 fullName = namespace + "-" + name;
3615
3616 if ( !prototype ) {
3617 prototype = base;
3618 base = $.Widget;
3619 }
3620
3621 // create selector for plugin
3622 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
3623 return !!$.data( elem, fullName );
3624 };
3625
3626 $[ namespace ] = $[ namespace ] || {};
3627 existingConstructor = $[ namespace ][ name ];
3628 constructor = $[ namespace ][ name ] = function( options, element ) {
3629 // allow instantiation without "new" keyword
3630 if ( !this._createWidget ) {
3631 return new constructor( options, element );
3632 }
3633
3634 // allow instantiation without initializing for simple inheritance
3635 // must use "new" keyword (the code above always passes args)
3636 if ( arguments.length ) {
3637 this._createWidget( options, element );
3638 }
3639 };
3640 // extend with the existing constructor to carry over any static properties
3641 $.extend( constructor, existingConstructor, {
3642 version: prototype.version,
3643 // copy the object used to create the prototype in case we need to
3644 // redefine the widget later
3645 _proto: $.extend( {}, prototype ),
3646 // track widgets that inherit from this widget in case this widget is
3647 // redefined after a widget inherits from it
3648 _childConstructors: []
3649 });
3650
3651 basePrototype = new base();
3652 // we need to make the options hash a property directly on the new instance
3653 // otherwise we'll modify the options hash on the prototype that we're
3654 // inheriting from
3655 basePrototype.options = $.widget.extend( {}, basePrototype.options );
3656 $.each( prototype, function( prop, value ) {
3657 if ( !$.isFunction( value ) ) {
3658 proxiedPrototype[ prop ] = value;
3659 return;
3660 }
3661 proxiedPrototype[ prop ] = (function() {
3662 var _super = function() {
3663 return base.prototype[ prop ].apply( this, arguments );
3664 },
3665 _superApply = function( args ) {
3666 return base.prototype[ prop ].apply( this, args );
3667 };
3668 return function() {
3669 var __super = this._super,
3670 __superApply = this._superApply,
3671 returnValue;
3672
3673 this._super = _super;
3674 this._superApply = _superApply;
3675
3676 returnValue = value.apply( this, arguments );
3677
3678 this._super = __super;
3679 this._superApply = __superApply;
3680
3681 return returnValue;
3682 };
3683 })();
3684 });
3685 constructor.prototype = $.widget.extend( basePrototype, {
3686 // TODO: remove support for widgetEventPrefix
3687 // always use the name + a colon as the prefix, e.g., draggable:start
3688 // don't prefix for widgets that aren't DOM-based
3689 widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
3690 }, proxiedPrototype, {
3691 constructor: constructor,
3692 namespace: namespace,
3693 widgetName: name,
3694 widgetFullName: fullName
3695 });
3696
3697 // If this widget is being redefined then we need to find all widgets that
3698 // are inheriting from it and redefine all of them so that they inherit from
3699 // the new version of this widget. We're essentially trying to replace one
3700 // level in the prototype chain.
3701 if ( existingConstructor ) {
3702 $.each( existingConstructor._childConstructors, function( i, child ) {
3703 var childPrototype = child.prototype;
3704
3705 // redefine the child widget using the same prototype that was
3706 // originally used, but inherit from the new version of the base
3707 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
3708 });
3709 // remove the list of existing child constructors from the old constructor
3710 // so the old child constructors can be garbage collected
3711 delete existingConstructor._childConstructors;
3712 } else {
3713 base._childConstructors.push( constructor );
3714 }
3715
3716 $.widget.bridge( name, constructor );
3717 };
3718
3719 $.widget.extend = function( target ) {
3720 var input = slice.call( arguments, 1 ),
3721 inputIndex = 0,
3722 inputLength = input.length,
3723 key,
3724 value;
3725 for ( ; inputIndex < inputLength; inputIndex++ ) {
3726 for ( key in input[ inputIndex ] ) {
3727 value = input[ inputIndex ][ key ];
3728 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
3729 // Clone objects
3730 if ( $.isPlainObject( value ) ) {
3731 target[ key ] = $.isPlainObject( target[ key ] ) ?
3732 $.widget.extend( {}, target[ key ], value ) :
3733 // Don't extend strings, arrays, etc. with objects
3734 $.widget.extend( {}, value );
3735 // Copy everything else by reference
3736 } else {
3737 target[ key ] = value;
3738 }
3739 }
3740 }
3741 }
3742 return target;
3743 };
3744
3745 $.widget.bridge = function( name, object ) {
3746 var fullName = object.prototype.widgetFullName || name;
3747 $.fn[ name ] = function( options ) {
3748 var isMethodCall = typeof options === "string",
3749 args = slice.call( arguments, 1 ),
3750 returnValue = this;
3751
3752 // allow multiple hashes to be passed on init
3753 options = !isMethodCall && args.length ?
3754 $.widget.extend.apply( null, [ options ].concat(args) ) :
3755 options;
3756
3757 if ( isMethodCall ) {
3758 this.each(function() {
3759 var methodValue,
3760 instance = $.data( this, fullName );
3761 if ( !instance ) {
3762 return $.error( "cannot call methods on " + name + " prior to initialization; " +
3763 "attempted to call method '" + options + "'" );
3764 }
3765 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
3766 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
3767 }
3768 methodValue = instance[ options ].apply( instance, args );
3769 if ( methodValue !== instance && methodValue !== undefined ) {
3770 returnValue = methodValue && methodValue.jquery ?
3771 returnValue.pushStack( methodValue.get() ) :
3772 methodValue;
3773 return false;
3774 }
3775 });
3776 } else {
3777 this.each(function() {
3778 var instance = $.data( this, fullName );
3779 if ( instance ) {
3780 instance.option( options || {} )._init();
3781 } else {
3782 $.data( this, fullName, new object( options, this ) );
3783 }
3784 });
3785 }
3786
3787 return returnValue;
3788 };
3789 };
3790
3791 $.Widget = function( /* options, element */ ) {};
3792 $.Widget._childConstructors = [];
3793
3794 $.Widget.prototype = {
3795 widgetName: "widget",
3796 widgetEventPrefix: "",
3797 defaultElement: "<div>",
3798 options: {
3799 disabled: false,
3800
3801 // callbacks
3802 create: null
3803 },
3804 _createWidget: function( options, element ) {
3805 element = $( element || this.defaultElement || this )[ 0 ];
3806 this.element = $( element );
3807 this.uuid = uuid++;
3808 this.eventNamespace = "." + this.widgetName + this.uuid;
3809 this.options = $.widget.extend( {},
3810 this.options,
3811 this._getCreateOptions(),
3812 options );
3813
3814 this.bindings = $();
3815 this.hoverable = $();
3816 this.focusable = $();
3817
3818 if ( element !== this ) {
3819 $.data( element, this.widgetFullName, this );
3820 this._on( true, this.element, {
3821 remove: function( event ) {
3822 if ( event.target === element ) {
3823 this.destroy();
3824 }
3825 }
3826 });
3827 this.document = $( element.style ?
3828 // element within the document
3829 element.ownerDocument :
3830 // element is window or document
3831 element.document || element );
3832 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
3833 }
3834
3835 this._create();
3836 this._trigger( "create", null, this._getCreateEventData() );
3837 this._init();
3838 },
3839 _getCreateOptions: $.noop,
3840 _getCreateEventData: $.noop,
3841 _create: $.noop,
3842 _init: $.noop,
3843
3844 destroy: function() {
3845 this._destroy();
3846 // we can probably remove the unbind calls in 2.0
3847 // all event bindings should go through this._on()
3848 this.element
3849 .unbind( this.eventNamespace )
3850 // 1.9 BC for #7810
3851 // TODO remove dual storage
3852 .removeData( this.widgetName )
3853 .removeData( this.widgetFullName )
3854 // support: jquery <1.6.3
3855 // http://bugs.jquery.com/ticket/9413
3856 .removeData( $.camelCase( this.widgetFullName ) );
3857 this.widget()
3858 .unbind( this.eventNamespace )
3859 .removeAttr( "aria-disabled" )
3860 .removeClass(
3861 this.widgetFullName + "-disabled " +
3862 "ui-state-disabled" );
3863
3864 // clean up events and states
3865 this.bindings.unbind( this.eventNamespace );
3866 this.hoverable.removeClass( "ui-state-hover" );
3867 this.focusable.removeClass( "ui-state-focus" );
3868 },
3869 _destroy: $.noop,
3870
3871 widget: function() {
3872 return this.element;
3873 },
3874
3875 option: function( key, value ) {
3876 var options = key,
3877 parts,
3878 curOption,
3879 i;
3880
3881 if ( arguments.length === 0 ) {
3882 // don't return a reference to the internal hash
3883 return $.widget.extend( {}, this.options );
3884 }
3885
3886 if ( typeof key === "string" ) {
3887 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
3888 options = {};
3889 parts = key.split( "." );
3890 key = parts.shift();
3891 if ( parts.length ) {
3892 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
3893 for ( i = 0; i < parts.length - 1; i++ ) {
3894 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
3895 curOption = curOption[ parts[ i ] ];
3896 }
3897 key = parts.pop();
3898 if ( value === undefined ) {
3899 return curOption[ key ] === undefined ? null : curOption[ key ];
3900 }
3901 curOption[ key ] = value;
3902 } else {
3903 if ( value === undefined ) {
3904 return this.options[ key ] === undefined ? null : this.options[ key ];
3905 }
3906 options[ key ] = value;
3907 }
3908 }
3909
3910 this._setOptions( options );
3911
3912 return this;
3913 },
3914 _setOptions: function( options ) {
3915 var key;
3916
3917 for ( key in options ) {
3918 this._setOption( key, options[ key ] );
3919 }
3920
3921 return this;
3922 },
3923 _setOption: function( key, value ) {
3924 this.options[ key ] = value;
3925
3926 if ( key === "disabled" ) {
3927 this.widget()
3928 .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
3929 .attr( "aria-disabled", value );
3930 this.hoverable.removeClass( "ui-state-hover" );
3931 this.focusable.removeClass( "ui-state-focus" );
3932 }
3933
3934 return this;
3935 },
3936
3937 enable: function() {
3938 return this._setOption( "disabled", false );
3939 },
3940 disable: function() {
3941 return this._setOption( "disabled", true );
3942 },
3943
3944 _on: function( suppressDisabledCheck, element, handlers ) {
3945 var delegateElement,
3946 instance = this;
3947
3948 // no suppressDisabledCheck flag, shuffle arguments
3949 if ( typeof suppressDisabledCheck !== "boolean" ) {
3950 handlers = element;
3951 element = suppressDisabledCheck;
3952 suppressDisabledCheck = false;
3953 }
3954
3955 // no element argument, shuffle and use this.element
3956 if ( !handlers ) {
3957 handlers = element;
3958 element = this.element;
3959 delegateElement = this.widget();
3960 } else {
3961 // accept selectors, DOM elements
3962 element = delegateElement = $( element );
3963 this.bindings = this.bindings.add( element );
3964 }
3965
3966 $.each( handlers, function( event, handler ) {
3967 function handlerProxy() {
3968 // allow widgets to customize the disabled handling
3969 // - disabled as an array instead of boolean
3970 // - disabled class as method for disabling individual parts
3971 if ( !suppressDisabledCheck &&
3972 ( instance.options.disabled === true ||
3973 $( this ).hasClass( "ui-state-disabled" ) ) ) {
3974 return;
3975 }
3976 return ( typeof handler === "string" ? instance[ handler ] : handler )
3977 .apply( instance, arguments );
3978 }
3979
3980 // copy the guid so direct unbinding works
3981 if ( typeof handler !== "string" ) {
3982 handlerProxy.guid = handler.guid =
3983 handler.guid || handlerProxy.guid || $.guid++;
3984 }
3985
3986 var match = event.match( /^(\w+)\s*(.*)$/ ),
3987 eventName = match[1] + instance.eventNamespace,
3988 selector = match[2];
3989 if ( selector ) {
3990 delegateElement.delegate( selector, eventName, handlerProxy );
3991 } else {
3992 element.bind( eventName, handlerProxy );
3993 }
3994 });
3995 },
3996
3997 _off: function( element, eventName ) {
3998 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
3999 element.unbind( eventName ).undelegate( eventName );
4000 },
4001
4002 _delay: function( handler, delay ) {
4003 function handlerProxy() {
4004 return ( typeof handler === "string" ? instance[ handler ] : handler )
4005 .apply( instance, arguments );
4006 }
4007 var instance = this;
4008 return setTimeout( handlerProxy, delay || 0 );
4009 },
4010
4011 _hoverable: function( element ) {
4012 this.hoverable = this.hoverable.add( element );
4013 this._on( element, {
4014 mouseenter: function( event ) {
4015 $( event.currentTarget ).addClass( "ui-state-hover" );
4016 },
4017 mouseleave: function( event ) {
4018 $( event.currentTarget ).removeClass( "ui-state-hover" );
4019 }
4020 });
4021 },
4022
4023 _focusable: function( element ) {
4024 this.focusable = this.focusable.add( element );
4025 this._on( element, {
4026 focusin: function( event ) {
4027 $( event.currentTarget ).addClass( "ui-state-focus" );
4028 },
4029 focusout: function( event ) {
4030 $( event.currentTarget ).removeClass( "ui-state-focus" );
4031 }
4032 });
4033 },
4034
4035 _trigger: function( type, event, data ) {
4036 var prop, orig,
4037 callback = this.options[ type ];
4038
4039 data = data || {};
4040 event = $.Event( event );
4041 event.type = ( type === this.widgetEventPrefix ?
4042 type :
4043 this.widgetEventPrefix + type ).toLowerCase();
4044 // the original event may come from any element
4045 // so we need to reset the target on the new event
4046 event.target = this.element[ 0 ];
4047
4048 // copy original event properties over to the new event
4049 orig = event.originalEvent;
4050 if ( orig ) {
4051 for ( prop in orig ) {
4052 if ( !( prop in event ) ) {
4053 event[ prop ] = orig[ prop ];
4054 }
4055 }
4056 }
4057
4058 this.element.trigger( event, data );
4059 return !( $.isFunction( callback ) &&
4060 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
4061 event.isDefaultPrevented() );
4062 }
4063 };
4064
4065 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
4066 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
4067 if ( typeof options === "string" ) {
4068 options = { effect: options };
4069 }
4070 var hasOptions,
4071 effectName = !options ?
4072 method :
4073 options === true || typeof options === "number" ?
4074 defaultEffect :
4075 options.effect || defaultEffect;
4076 options = options || {};
4077 if ( typeof options === "number" ) {
4078 options = { duration: options };
4079 }
4080 hasOptions = !$.isEmptyObject( options );
4081 options.complete = callback;
4082 if ( options.delay ) {
4083 element.delay( options.delay );
4084 }
4085 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
4086 element[ method ]( options );
4087 } else if ( effectName !== method && element[ effectName ] ) {
4088 element[ effectName ]( options.duration, options.easing, callback );
4089 } else {
4090 element.queue(function( next ) {
4091 $( this )[ method ]();
4092 if ( callback ) {
4093 callback.call( element[ 0 ] );
4094 }
4095 next();
4096 });
4097 }
4098 };
4099 });
4100
4101 })( jQuery );
4102 (function( $, undefined ) {
4103
4104 var mouseHandled = false;
4105 $( document ).mouseup( function() {
4106 mouseHandled = false;
4107 });
4108
4109 $.widget("ui.mouse", {
4110 version: "1.10.3",
4111 options: {
4112 cancel: "input,textarea,button,select,option",
4113 distance: 1,
4114 delay: 0
4115 },
4116 _mouseInit: function() {
4117 var that = this;
4118
4119 this.element
4120 .bind("mousedown."+this.widgetName, function(event) {
4121 return that._mouseDown(event);
4122 })
4123 .bind("click."+this.widgetName, function(event) {
4124 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
4125 $.removeData(event.target, that.widgetName + ".preventClickEvent");
4126 event.stopImmediatePropagation();
4127 return false;
4128 }
4129 });
4130
4131 this.started = false;
4132 },
4133
4134 // TODO: make sure destroying one instance of mouse doesn't mess with
4135 // other instances of mouse
4136 _mouseDestroy: function() {
4137 this.element.unbind("."+this.widgetName);
4138 if ( this._mouseMoveDelegate ) {
4139 $(document)
4140 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
4141 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
4142 }
4143 },
4144
4145 _mouseDown: function(event) {
4146 // don't let more than one widget handle mouseStart
4147 if( mouseHandled ) { return; }
4148
4149 // we may have missed mouseup (out of window)
4150 (this._mouseStarted && this._mouseUp(event));
4151
4152 this._mouseDownEvent = event;
4153
4154 var that = this,
4155 btnIsLeft = (event.which === 1),
4156 // event.target.nodeName works around a bug in IE 8 with
4157 // disabled inputs (#7620)
4158 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
4159 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
4160 return true;
4161 }
4162
4163 this.mouseDelayMet = !this.options.delay;
4164 if (!this.mouseDelayMet) {
4165 this._mouseDelayTimer = setTimeout(function() {
4166 that.mouseDelayMet = true;
4167 }, this.options.delay);
4168 }
4169
4170 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
4171 this._mouseStarted = (this._mouseStart(event) !== false);
4172 if (!this._mouseStarted) {
4173 event.preventDefault();
4174 return true;
4175 }
4176 }
4177
4178 // Click event may never have fired (Gecko & Opera)
4179 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
4180 $.removeData(event.target, this.widgetName + ".preventClickEvent");
4181 }
4182
4183 // these delegates are required to keep context
4184 this._mouseMoveDelegate = function(event) {
4185 return that._mouseMove(event);
4186 };
4187 this._mouseUpDelegate = function(event) {
4188 return that._mouseUp(event);
4189 };
4190 $(document)
4191 .bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
4192 .bind("mouseup."+this.widgetName, this._mouseUpDelegate);
4193
4194 event.preventDefault();
4195
4196 mouseHandled = true;
4197 return true;
4198 },
4199
4200 _mouseMove: function(event) {
4201 // IE mouseup check - mouseup happened when mouse was out of window
4202 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
4203 return this._mouseUp(event);
4204 }
4205
4206 if (this._mouseStarted) {
4207 this._mouseDrag(event);
4208 return event.preventDefault();
4209 }
4210
4211 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
4212 this._mouseStarted =
4213 (this._mouseStart(this._mouseDownEvent, event) !== false);
4214 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
4215 }
4216
4217 return !this._mouseStarted;
4218 },
4219
4220 _mouseUp: function(event) {
4221 $(document)
4222 .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
4223 .unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
4224
4225 if (this._mouseStarted) {
4226 this._mouseStarted = false;
4227
4228 if (event.target === this._mouseDownEvent.target) {
4229 $.data(event.target, this.widgetName + ".preventClickEvent", true);
4230 }
4231
4232 this._mouseStop(event);
4233 }
4234
4235 return false;
4236 },
4237
4238 _mouseDistanceMet: function(event) {
4239 return (Math.max(
4240 Math.abs(this._mouseDownEvent.pageX - event.pageX),
4241 Math.abs(this._mouseDownEvent.pageY - event.pageY)
4242 ) >= this.options.distance
4243 );
4244 },
4245
4246 _mouseDelayMet: function(/* event */) {
4247 return this.mouseDelayMet;
4248 },
4249
4250 // These are placeholder methods, to be overriden by extending plugin
4251 _mouseStart: function(/* event */) {},
4252 _mouseDrag: function(/* event */) {},
4253 _mouseStop: function(/* event */) {},
4254 _mouseCapture: function(/* event */) { return true; }
4255 });
4256
4257 })(jQuery);
4258 (function( $, undefined ) {
4259
4260 $.ui = $.ui || {};
4261
4262 var cachedScrollbarWidth,
4263 max = Math.max,
4264 abs = Math.abs,
4265 round = Math.round,
4266 rhorizontal = /left|center|right/,
4267 rvertical = /top|center|bottom/,
4268 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
4269 rposition = /^\w+/,
4270 rpercent = /%$/,
4271 _position = $.fn.position;
4272
4273 function getOffsets( offsets, width, height ) {
4274 return [
4275 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
4276 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
4277 ];
4278 }
4279
4280 function parseCss( element, property ) {
4281 return parseInt( $.css( element, property ), 10 ) || 0;
4282 }
4283
4284 function getDimensions( elem ) {
4285 var raw = elem[0];
4286 if ( raw.nodeType === 9 ) {
4287 return {
4288 width: elem.width(),
4289 height: elem.height(),
4290 offset: { top: 0, left: 0 }
4291 };
4292 }
4293 if ( $.isWindow( raw ) ) {
4294 return {
4295 width: elem.width(),
4296 height: elem.height(),
4297 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
4298 };
4299 }
4300 if ( raw.preventDefault ) {
4301 return {
4302 width: 0,
4303 height: 0,
4304 offset: { top: raw.pageY, left: raw.pageX }
4305 };
4306 }
4307 return {
4308 width: elem.outerWidth(),
4309 height: elem.outerHeight(),
4310 offset: elem.offset()
4311 };
4312 }
4313
4314 $.position = {
4315 scrollbarWidth: function() {
4316 if ( cachedScrollbarWidth !== undefined ) {
4317 return cachedScrollbarWidth;
4318 }
4319 var w1, w2,
4320 div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
4321 innerDiv = div.children()[0];
4322
4323 $( "body" ).append( div );
4324 w1 = innerDiv.offsetWidth;
4325 div.css( "overflow", "scroll" );
4326
4327 w2 = innerDiv.offsetWidth;
4328
4329 if ( w1 === w2 ) {
4330 w2 = div[0].clientWidth;
4331 }
4332
4333 div.remove();
4334
4335 return (cachedScrollbarWidth = w1 - w2);
4336 },
4337 getScrollInfo: function( within ) {
4338 var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
4339 overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
4340 hasOverflowX = overflowX === "scroll" ||
4341 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
4342 hasOverflowY = overflowY === "scroll" ||
4343 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
4344 return {
4345 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
4346 height: hasOverflowX ? $.position.scrollbarWidth() : 0
4347 };
4348 },
4349 getWithinInfo: function( element ) {
4350 var withinElement = $( element || window ),
4351 isWindow = $.isWindow( withinElement[0] );
4352 return {
4353 element: withinElement,
4354 isWindow: isWindow,
4355 offset: withinElement.offset() || { left: 0, top: 0 },
4356 scrollLeft: withinElement.scrollLeft(),
4357 scrollTop: withinElement.scrollTop(),
4358 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
4359 height: isWindow ? withinElement.height() : withinElement.outerHeight()
4360 };
4361 }
4362 };
4363
4364 $.fn.position = function( options ) {
4365 if ( !options || !options.of ) {
4366 return _position.apply( this, arguments );
4367 }
4368
4369 // make a copy, we don't want to modify arguments
4370 options = $.extend( {}, options );
4371
4372 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
4373 target = $( options.of ),
4374 within = $.position.getWithinInfo( options.within ),
4375 scrollInfo = $.position.getScrollInfo( within ),
4376 collision = ( options.collision || "flip" ).split( " " ),
4377 offsets = {};
4378
4379 dimensions = getDimensions( target );
4380 if ( target[0].preventDefault ) {
4381 // force left top to allow flipping
4382 options.at = "left top";
4383 }
4384 targetWidth = dimensions.width;
4385 targetHeight = dimensions.height;
4386 targetOffset = dimensions.offset;
4387 // clone to reuse original targetOffset later
4388 basePosition = $.extend( {}, targetOffset );
4389
4390 // force my and at to have valid horizontal and vertical positions
4391 // if a value is missing or invalid, it will be converted to center
4392 $.each( [ "my", "at" ], function() {
4393 var pos = ( options[ this ] || "" ).split( " " ),
4394 horizontalOffset,
4395 verticalOffset;
4396
4397 if ( pos.length === 1) {
4398 pos = rhorizontal.test( pos[ 0 ] ) ?
4399 pos.concat( [ "center" ] ) :
4400 rvertical.test( pos[ 0 ] ) ?
4401 [ "center" ].concat( pos ) :
4402 [ "center", "center" ];
4403 }
4404 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
4405 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
4406
4407 // calculate offsets
4408 horizontalOffset = roffset.exec( pos[ 0 ] );
4409 verticalOffset = roffset.exec( pos[ 1 ] );
4410 offsets[ this ] = [
4411 horizontalOffset ? horizontalOffset[ 0 ] : 0,
4412 verticalOffset ? verticalOffset[ 0 ] : 0
4413 ];
4414
4415 // reduce to just the positions without the offsets
4416 options[ this ] = [
4417 rposition.exec( pos[ 0 ] )[ 0 ],
4418 rposition.exec( pos[ 1 ] )[ 0 ]
4419 ];
4420 });
4421
4422 // normalize collision option
4423 if ( collision.length === 1 ) {
4424 collision[ 1 ] = collision[ 0 ];
4425 }
4426
4427 if ( options.at[ 0 ] === "right" ) {
4428 basePosition.left += targetWidth;
4429 } else if ( options.at[ 0 ] === "center" ) {
4430 basePosition.left += targetWidth / 2;
4431 }
4432
4433 if ( options.at[ 1 ] === "bottom" ) {
4434 basePosition.top += targetHeight;
4435 } else if ( options.at[ 1 ] === "center" ) {
4436 basePosition.top += targetHeight / 2;
4437 }
4438
4439 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
4440 basePosition.left += atOffset[ 0 ];
4441 basePosition.top += atOffset[ 1 ];
4442
4443 return this.each(function() {
4444 var collisionPosition, using,
4445 elem = $( this ),
4446 elemWidth = elem.outerWidth(),
4447 elemHeight = elem.outerHeight(),
4448 marginLeft = parseCss( this, "marginLeft" ),
4449 marginTop = parseCss( this, "marginTop" ),
4450 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
4451 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
4452 position = $.extend( {}, basePosition ),
4453 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
4454
4455 if ( options.my[ 0 ] === "right" ) {
4456 position.left -= elemWidth;
4457 } else if ( options.my[ 0 ] === "center" ) {
4458 position.left -= elemWidth / 2;
4459 }
4460
4461 if ( options.my[ 1 ] === "bottom" ) {
4462 position.top -= elemHeight;
4463 } else if ( options.my[ 1 ] === "center" ) {
4464 position.top -= elemHeight / 2;
4465 }
4466
4467 position.left += myOffset[ 0 ];
4468 position.top += myOffset[ 1 ];
4469
4470 // if the browser doesn't support fractions, then round for consistent results
4471 if ( !$.support.offsetFractions ) {
4472 position.left = round( position.left );
4473 position.top = round( position.top );
4474 }
4475
4476 collisionPosition = {
4477 marginLeft: marginLeft,
4478 marginTop: marginTop
4479 };
4480
4481 $.each( [ "left", "top" ], function( i, dir ) {
4482 if ( $.ui.position[ collision[ i ] ] ) {
4483 $.ui.position[ collision[ i ] ][ dir ]( position, {
4484 targetWidth: targetWidth,
4485 targetHeight: targetHeight,
4486 elemWidth: elemWidth,
4487 elemHeight: elemHeight,
4488 collisionPosition: collisionPosition,
4489 collisionWidth: collisionWidth,
4490 collisionHeight: collisionHeight,
4491 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
4492 my: options.my,
4493 at: options.at,
4494 within: within,
4495 elem : elem
4496 });
4497 }
4498 });
4499
4500 if ( options.using ) {
4501 // adds feedback as second argument to using callback, if present
4502 using = function( props ) {
4503 var left = targetOffset.left - position.left,
4504 right = left + targetWidth - elemWidth,
4505 top = targetOffset.top - position.top,
4506 bottom = top + targetHeight - elemHeight,
4507 feedback = {
4508 target: {
4509 element: target,
4510 left: targetOffset.left,
4511 top: targetOffset.top,
4512 width: targetWidth,
4513 height: targetHeight
4514 },
4515 element: {
4516 element: elem,
4517 left: position.left,
4518 top: position.top,
4519 width: elemWidth,
4520 height: elemHeight
4521 },
4522 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
4523 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
4524 };
4525 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
4526 feedback.horizontal = "center";
4527 }
4528 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
4529 feedback.vertical = "middle";
4530 }
4531 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
4532 feedback.important = "horizontal";
4533 } else {
4534 feedback.important = "vertical";
4535 }
4536 options.using.call( this, props, feedback );
4537 };
4538 }
4539
4540 elem.offset( $.extend( position, { using: using } ) );
4541 });
4542 };
4543
4544 $.ui.position = {
4545 fit: {
4546 left: function( position, data ) {
4547 var within = data.within,
4548 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
4549 outerWidth = within.width,
4550 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
4551 overLeft = withinOffset - collisionPosLeft,
4552 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
4553 newOverRight;
4554
4555 // element is wider than within
4556 if ( data.collisionWidth > outerWidth ) {
4557 // element is initially over the left side of within
4558 if ( overLeft > 0 && overRight <= 0 ) {
4559 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
4560 position.left += overLeft - newOverRight;
4561 // element is initially over right side of within
4562 } else if ( overRight > 0 && overLeft <= 0 ) {
4563 position.left = withinOffset;
4564 // element is initially over both left and right sides of within
4565 } else {
4566 if ( overLeft > overRight ) {
4567 position.left = withinOffset + outerWidth - data.collisionWidth;
4568 } else {
4569 position.left = withinOffset;
4570 }
4571 }
4572 // too far left -> align with left edge
4573 } else if ( overLeft > 0 ) {
4574 position.left += overLeft;
4575 // too far right -> align with right edge
4576 } else if ( overRight > 0 ) {
4577 position.left -= overRight;
4578 // adjust based on position and margin
4579 } else {
4580 position.left = max( position.left - collisionPosLeft, position.left );
4581 }
4582 },
4583 top: function( position, data ) {
4584 var within = data.within,
4585 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
4586 outerHeight = data.within.height,
4587 collisionPosTop = position.top - data.collisionPosition.marginTop,
4588 overTop = withinOffset - collisionPosTop,
4589 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
4590 newOverBottom;
4591
4592 // element is taller than within
4593 if ( data.collisionHeight > outerHeight ) {
4594 // element is initially over the top of within
4595 if ( overTop > 0 && overBottom <= 0 ) {
4596 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
4597 position.top += overTop - newOverBottom;
4598 // element is initially over bottom of within
4599 } else if ( overBottom > 0 && overTop <= 0 ) {
4600 position.top = withinOffset;
4601 // element is initially over both top and bottom of within
4602 } else {
4603 if ( overTop > overBottom ) {
4604 position.top = withinOffset + outerHeight - data.collisionHeight;
4605 } else {
4606 position.top = withinOffset;
4607 }
4608 }
4609 // too far up -> align with top
4610 } else if ( overTop > 0 ) {
4611 position.top += overTop;
4612 // too far down -> align with bottom edge
4613 } else if ( overBottom > 0 ) {
4614 position.top -= overBottom;
4615 // adjust based on position and margin
4616 } else {
4617 position.top = max( position.top - collisionPosTop, position.top );
4618 }
4619 }
4620 },
4621 flip: {
4622 left: function( position, data ) {
4623 var within = data.within,
4624 withinOffset = within.offset.left + within.scrollLeft,
4625 outerWidth = within.width,
4626 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
4627 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
4628 overLeft = collisionPosLeft - offsetLeft,
4629 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
4630 myOffset = data.my[ 0 ] === "left" ?
4631 -data.elemWidth :
4632 data.my[ 0 ] === "right" ?
4633 data.elemWidth :
4634 0,
4635 atOffset = data.at[ 0 ] === "left" ?
4636 data.targetWidth :
4637 data.at[ 0 ] === "right" ?
4638 -data.targetWidth :
4639 0,
4640 offset = -2 * data.offset[ 0 ],
4641 newOverRight,
4642 newOverLeft;
4643
4644 if ( overLeft < 0 ) {
4645 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
4646 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
4647 position.left += myOffset + atOffset + offset;
4648 }
4649 }
4650 else if ( overRight > 0 ) {
4651 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
4652 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
4653 position.left += myOffset + atOffset + offset;
4654 }
4655 }
4656 },
4657 top: function( position, data ) {
4658 var within = data.within,
4659 withinOffset = within.offset.top + within.scrollTop,
4660 outerHeight = within.height,
4661 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
4662 collisionPosTop = position.top - data.collisionPosition.marginTop,
4663 overTop = collisionPosTop - offsetTop,
4664 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
4665 top = data.my[ 1 ] === "top",
4666 myOffset = top ?
4667 -data.elemHeight :
4668 data.my[ 1 ] === "bottom" ?
4669 data.elemHeight :
4670 0,
4671 atOffset = data.at[ 1 ] === "top" ?
4672 data.targetHeight :
4673 data.at[ 1 ] === "bottom" ?
4674 -data.targetHeight :
4675 0,
4676 offset = -2 * data.offset[ 1 ],
4677 newOverTop,
4678 newOverBottom;
4679 if ( overTop < 0 ) {
4680 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
4681 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
4682 position.top += myOffset + atOffset + offset;
4683 }
4684 }
4685 else if ( overBottom > 0 ) {
4686 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
4687 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
4688 position.top += myOffset + atOffset + offset;
4689 }
4690 }
4691 }
4692 },
4693 flipfit: {
4694 left: function() {
4695 $.ui.position.flip.left.apply( this, arguments );
4696 $.ui.position.fit.left.apply( this, arguments );
4697 },
4698 top: function() {
4699 $.ui.position.flip.top.apply( this, arguments );
4700 $.ui.position.fit.top.apply( this, arguments );
4701 }
4702 }
4703 };
4704
4705 // fraction support test
4706 (function () {
4707 var testElement, testElementParent, testElementStyle, offsetLeft, i,
4708 body = document.getElementsByTagName( "body" )[ 0 ],
4709 div = document.createElement( "div" );
4710
4711 //Create a "fake body" for testing based on method used in jQuery.support
4712 testElement = document.createElement( body ? "div" : "body" );
4713 testElementStyle = {
4714 visibility: "hidden",
4715 width: 0,
4716 height: 0,
4717 border: 0,
4718 margin: 0,
4719 background: "none"
4720 };
4721 if ( body ) {
4722 $.extend( testElementStyle, {
4723 position: "absolute",
4724 left: "-1000px",
4725 top: "-1000px"
4726 });
4727 }
4728 for ( i in testElementStyle ) {
4729 testElement.style[ i ] = testElementStyle[ i ];
4730 }
4731 testElement.appendChild( div );
4732 testElementParent = body || document.documentElement;
4733 testElementParent.insertBefore( testElement, testElementParent.firstChild );
4734
4735 div.style.cssText = "position: absolute; left: 10.7432222px;";
4736
4737 offsetLeft = $( div ).offset().left;
4738 $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
4739
4740 testElement.innerHTML = "";
4741 testElementParent.removeChild( testElement );
4742 })();
4743
4744 }( jQuery ) );
4745 (function( $, undefined ) {
4746
4747 $.widget("ui.draggable", $.ui.mouse, {
4748 version: "1.10.3",
4749 widgetEventPrefix: "drag",
4750 options: {
4751 addClasses: true,
4752 appendTo: "parent",
4753 axis: false,
4754 connectToSortable: false,
4755 containment: false,
4756 cursor: "auto",
4757 cursorAt: false,
4758 grid: false,
4759 handle: false,
4760 helper: "original",
4761 iframeFix: false,
4762 opacity: false,
4763 refreshPositions: false,
4764 revert: false,
4765 revertDuration: 500,
4766 scope: "default",
4767 scroll: true,
4768 scrollSensitivity: 20,
4769 scrollSpeed: 20,
4770 snap: false,
4771 snapMode: "both",
4772 snapTolerance: 20,
4773 stack: false,
4774 zIndex: false,
4775
4776 // callbacks
4777 drag: null,
4778 start: null,
4779 stop: null
4780 },
4781 _create: function() {
4782
4783 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
4784 this.element[0].style.position = "relative";
4785 }
4786 if (this.options.addClasses){
4787 this.element.addClass("ui-draggable");
4788 }
4789 if (this.options.disabled){
4790 this.element.addClass("ui-draggable-disabled");
4791 }
4792
4793 this._mouseInit();
4794
4795 },
4796
4797 _destroy: function() {
4798 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
4799 this._mouseDestroy();
4800 },
4801
4802 _mouseCapture: function(event) {
4803
4804 var o = this.options;
4805
4806 // among others, prevent a drag on a resizable-handle
4807 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
4808 return false;
4809 }
4810
4811 //Quit if we're not on a valid handle
4812 this.handle = this._getHandle(event);
4813 if (!this.handle) {
4814 return false;
4815 }
4816
4817 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
4818 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
4819 .css({
4820 width: this.offsetWidth+"px", height: this.offsetHeight+"px",
4821 position: "absolute", opacity: "0.001", zIndex: 1000
4822 })
4823 .css($(this).offset())
4824 .appendTo("body");
4825 });
4826
4827 return true;
4828
4829 },
4830
4831 _mouseStart: function(event) {
4832
4833 var o = this.options;
4834
4835 //Create and append the visible helper
4836 this.helper = this._createHelper(event);
4837
4838 this.helper.addClass("ui-draggable-dragging");
4839
4840 //Cache the helper size
4841 this._cacheHelperProportions();
4842
4843 //If ddmanager is used for droppables, set the global draggable
4844 if($.ui.ddmanager) {
4845 $.ui.ddmanager.current = this;
4846 }
4847
4848 /*
4849 * - Position generation -
4850 * This block generates everything position related - it's the core of draggables.
4851 */
4852
4853 //Cache the margins of the original element
4854 this._cacheMargins();
4855
4856 //Store the helper's css position
4857 this.cssPosition = this.helper.css( "position" );
4858 this.scrollParent = this.helper.scrollParent();
4859 this.offsetParent = this.helper.offsetParent();
4860 this.offsetParentCssPosition = this.offsetParent.css( "position" );
4861
4862 //The element's absolute position on the page minus margins
4863 this.offset = this.positionAbs = this.element.offset();
4864 this.offset = {
4865 top: this.offset.top - this.margins.top,
4866 left: this.offset.left - this.margins.left
4867 };
4868
4869 //Reset scroll cache
4870 this.offset.scroll = false;
4871
4872 $.extend(this.offset, {
4873 click: { //Where the click happened, relative to the element
4874 left: event.pageX - this.offset.left,
4875 top: event.pageY - this.offset.top
4876 },
4877 parent: this._getParentOffset(),
4878 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
4879 });
4880
4881 //Generate the original position
4882 this.originalPosition = this.position = this._generatePosition(event);
4883 this.originalPageX = event.pageX;
4884 this.originalPageY = event.pageY;
4885
4886 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
4887 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
4888
4889 //Set a containment if given in the options
4890 this._setContainment();
4891
4892 //Trigger event + callbacks
4893 if(this._trigger("start", event) === false) {
4894 this._clear();
4895 return false;
4896 }
4897
4898 //Recache the helper size
4899 this._cacheHelperProportions();
4900
4901 //Prepare the droppable offsets
4902 if ($.ui.ddmanager && !o.dropBehaviour) {
4903 $.ui.ddmanager.prepareOffsets(this, event);
4904 }
4905
4906
4907 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
4908
4909 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
4910 if ( $.ui.ddmanager ) {
4911 $.ui.ddmanager.dragStart(this, event);
4912 }
4913
4914 return true;
4915 },
4916
4917 _mouseDrag: function(event, noPropagation) {
4918 // reset any necessary cached properties (see #5009)
4919 if ( this.offsetParentCssPosition === "fixed" ) {
4920 this.offset.parent = this._getParentOffset();
4921 }
4922
4923 //Compute the helpers position
4924 this.position = this._generatePosition(event);
4925 this.positionAbs = this._convertPositionTo("absolute");
4926
4927 //Call plugins and callbacks and use the resulting position if something is returned
4928 if (!noPropagation) {
4929 var ui = this._uiHash();
4930 if(this._trigger("drag", event, ui) === false) {
4931 this._mouseUp({});
4932 return false;
4933 }
4934 this.position = ui.position;
4935 }
4936
4937 if(!this.options.axis || this.options.axis !== "y") {
4938 this.helper[0].style.left = this.position.left+"px";
4939 }
4940 if(!this.options.axis || this.options.axis !== "x") {
4941 this.helper[0].style.top = this.position.top+"px";
4942 }
4943 if($.ui.ddmanager) {
4944 $.ui.ddmanager.drag(this, event);
4945 }
4946
4947 return false;
4948 },
4949
4950 _mouseStop: function(event) {
4951
4952 //If we are using droppables, inform the manager about the drop
4953 var that = this,
4954 dropped = false;
4955 if ($.ui.ddmanager && !this.options.dropBehaviour) {
4956 dropped = $.ui.ddmanager.drop(this, event);
4957 }
4958
4959 //if a drop comes from outside (a sortable)
4960 if(this.dropped) {
4961 dropped = this.dropped;
4962 this.dropped = false;
4963 }
4964
4965 //if the original element is no longer in the DOM don't bother to continue (see #8269)
4966 if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
4967 return false;
4968 }
4969
4970 if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
4971 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
4972 if(that._trigger("stop", event) !== false) {
4973 that._clear();
4974 }
4975 });
4976 } else {
4977 if(this._trigger("stop", event) !== false) {
4978 this._clear();
4979 }
4980 }
4981
4982 return false;
4983 },
4984
4985 _mouseUp: function(event) {
4986 //Remove frame helpers
4987 $("div.ui-draggable-iframeFix").each(function() {
4988 this.parentNode.removeChild(this);
4989 });
4990
4991 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
4992 if( $.ui.ddmanager ) {
4993 $.ui.ddmanager.dragStop(this, event);
4994 }
4995
4996 return $.ui.mouse.prototype._mouseUp.call(this, event);
4997 },
4998
4999 cancel: function() {
5000
5001 if(this.helper.is(".ui-draggable-dragging")) {
5002 this._mouseUp({});
5003 } else {
5004 this._clear();
5005 }
5006
5007 return this;
5008
5009 },
5010
5011 _getHandle: function(event) {
5012 return this.options.handle ?
5013 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
5014 true;
5015 },
5016
5017 _createHelper: function(event) {
5018
5019 var o = this.options,
5020 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
5021
5022 if(!helper.parents("body").length) {
5023 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
5024 }
5025
5026 if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
5027 helper.css("position", "absolute");
5028 }
5029
5030 return helper;
5031
5032 },
5033
5034 _adjustOffsetFromHelper: function(obj) {
5035 if (typeof obj === "string") {
5036 obj = obj.split(" ");
5037 }
5038 if ($.isArray(obj)) {
5039 obj = {left: +obj[0], top: +obj[1] || 0};
5040 }
5041 if ("left" in obj) {
5042 this.offset.click.left = obj.left + this.margins.left;
5043 }
5044 if ("right" in obj) {
5045 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
5046 }
5047 if ("top" in obj) {
5048 this.offset.click.top = obj.top + this.margins.top;
5049 }
5050 if ("bottom" in obj) {
5051 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
5052 }
5053 },
5054
5055 _getParentOffset: function() {
5056
5057 //Get the offsetParent and cache its position
5058 var po = this.offsetParent.offset();
5059
5060 // This is a special case where we need to modify a offset calculated on start, since the following happened:
5061 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
5062 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
5063 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
5064 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
5065 po.left += this.scrollParent.scrollLeft();
5066 po.top += this.scrollParent.scrollTop();
5067 }
5068
5069 //This needs to be actually done for all browsers, since pageX/pageY includes this information
5070 //Ugly IE fix
5071 if((this.offsetParent[0] === document.body) ||
5072 (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
5073 po = { top: 0, left: 0 };
5074 }
5075
5076 return {
5077 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
5078 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
5079 };
5080
5081 },
5082
5083 _getRelativeOffset: function() {
5084
5085 if(this.cssPosition === "relative") {
5086 var p = this.element.position();
5087 return {
5088 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
5089 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
5090 };
5091 } else {
5092 return { top: 0, left: 0 };
5093 }
5094
5095 },
5096
5097 _cacheMargins: function() {
5098 this.margins = {
5099 left: (parseInt(this.element.css("marginLeft"),10) || 0),
5100 top: (parseInt(this.element.css("marginTop"),10) || 0),
5101 right: (parseInt(this.element.css("marginRight"),10) || 0),
5102 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
5103 };
5104 },
5105
5106 _cacheHelperProportions: function() {
5107 this.helperProportions = {
5108 width: this.helper.outerWidth(),
5109 height: this.helper.outerHeight()
5110 };
5111 },
5112
5113 _setContainment: function() {
5114
5115 var over, c, ce,
5116 o = this.options;
5117
5118 if ( !o.containment ) {
5119 this.containment = null;
5120 return;
5121 }
5122
5123 if ( o.containment === "window" ) {
5124 this.containment = [
5125 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
5126 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
5127 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
5128 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
5129 ];
5130 return;
5131 }
5132
5133 if ( o.containment === "document") {
5134 this.containment = [
5135 0,
5136 0,
5137 $( document ).width() - this.helperProportions.width - this.margins.left,
5138 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
5139 ];
5140 return;
5141 }
5142
5143 if ( o.containment.constructor === Array ) {
5144 this.containment = o.containment;
5145 return;
5146 }
5147
5148 if ( o.containment === "parent" ) {
5149 o.containment = this.helper[ 0 ].parentNode;
5150 }
5151
5152 c = $( o.containment );
5153 ce = c[ 0 ];
5154
5155 if( !ce ) {
5156 return;
5157 }
5158
5159 over = c.css( "overflow" ) !== "hidden";
5160
5161 this.containment = [
5162 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
5163 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
5164 ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
5165 ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom
5166 ];
5167 this.relative_container = c;
5168 },
5169
5170 _convertPositionTo: function(d, pos) {
5171
5172 if(!pos) {
5173 pos = this.position;
5174 }
5175
5176 var mod = d === "absolute" ? 1 : -1,
5177 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
5178
5179 //Cache the scroll
5180 if (!this.offset.scroll) {
5181 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
5182 }
5183
5184 return {
5185 top: (
5186 pos.top + // The absolute mouse position
5187 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
5188 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
5189 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
5190 ),
5191 left: (
5192 pos.left + // The absolute mouse position
5193 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
5194 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
5195 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
5196 )
5197 };
5198
5199 },
5200
5201 _generatePosition: function(event) {
5202
5203 var containment, co, top, left,
5204 o = this.options,
5205 scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
5206 pageX = event.pageX,
5207 pageY = event.pageY;
5208
5209 //Cache the scroll
5210 if (!this.offset.scroll) {
5211 this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
5212 }
5213
5214 /*
5215 * - Position constraining -
5216 * Constrain the position to a mix of grid, containment.
5217 */
5218
5219 // If we are not dragging yet, we won't check for options
5220 if ( this.originalPosition ) {
5221 if ( this.containment ) {
5222 if ( this.relative_container ){
5223 co = this.relative_container.offset();
5224 containment = [
5225 this.containment[ 0 ] + co.left,
5226 this.containment[ 1 ] + co.top,
5227 this.containment[ 2 ] + co.left,
5228 this.containment[ 3 ] + co.top
5229 ];
5230 }
5231 else {
5232 containment = this.containment;
5233 }
5234
5235 if(event.pageX - this.offset.click.left < containment[0]) {
5236 pageX = containment[0] + this.offset.click.left;
5237 }
5238 if(event.pageY - this.offset.click.top < containment[1]) {
5239 pageY = containment[1] + this.offset.click.top;
5240 }
5241 if(event.pageX - this.offset.click.left > containment[2]) {
5242 pageX = containment[2] + this.offset.click.left;
5243 }
5244 if(event.pageY - this.offset.click.top > containment[3]) {
5245 pageY = containment[3] + this.offset.click.top;
5246 }
5247 }
5248
5249 if(o.grid) {
5250 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
5251 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
5252 pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
5253
5254 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
5255 pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
5256 }
5257
5258 }
5259
5260 return {
5261 top: (
5262 pageY - // The absolute mouse position
5263 this.offset.click.top - // Click offset (relative to the element)
5264 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
5265 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
5266 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
5267 ),
5268 left: (
5269 pageX - // The absolute mouse position
5270 this.offset.click.left - // Click offset (relative to the element)
5271 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
5272 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
5273 ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
5274 )
5275 };
5276
5277 },
5278
5279 _clear: function() {
5280 this.helper.removeClass("ui-draggable-dragging");
5281 if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
5282 this.helper.remove();
5283 }
5284 this.helper = null;
5285 this.cancelHelperRemoval = false;
5286 },
5287
5288 // From now on bulk stuff - mainly helpers
5289
5290 _trigger: function(type, event, ui) {
5291 ui = ui || this._uiHash();
5292 $.ui.plugin.call(this, type, [event, ui]);
5293 //The absolute position has to be recalculated after plugins
5294 if(type === "drag") {
5295 this.positionAbs = this._convertPositionTo("absolute");
5296 }
5297 return $.Widget.prototype._trigger.call(this, type, event, ui);
5298 },
5299
5300 plugins: {},
5301
5302 _uiHash: function() {
5303 return {
5304 helper: this.helper,
5305 position: this.position,
5306 originalPosition: this.originalPosition,
5307 offset: this.positionAbs
5308 };
5309 }
5310
5311 });
5312
5313 $.ui.plugin.add("draggable", "connectToSortable", {
5314 start: function(event, ui) {
5315
5316 var inst = $(this).data("ui-draggable"), o = inst.options,
5317 uiSortable = $.extend({}, ui, { item: inst.element });
5318 inst.sortables = [];
5319 $(o.connectToSortable).each(function() {
5320 var sortable = $.data(this, "ui-sortable");
5321 if (sortable && !sortable.options.disabled) {
5322 inst.sortables.push({
5323 instance: sortable,
5324 shouldRevert: sortable.options.revert
5325 });
5326 sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
5327 sortable._trigger("activate", event, uiSortable);
5328 }
5329 });
5330
5331 },
5332 stop: function(event, ui) {
5333
5334 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
5335 var inst = $(this).data("ui-draggable"),
5336 uiSortable = $.extend({}, ui, { item: inst.element });
5337
5338 $.each(inst.sortables, function() {
5339 if(this.instance.isOver) {
5340
5341 this.instance.isOver = 0;
5342
5343 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
5344 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
5345
5346 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
5347 if(this.shouldRevert) {
5348 this.instance.options.revert = this.shouldRevert;
5349 }
5350
5351 //Trigger the stop of the sortable
5352 this.instance._mouseStop(event);
5353
5354 this.instance.options.helper = this.instance.options._helper;
5355
5356 //If the helper has been the original item, restore properties in the sortable
5357 if(inst.options.helper === "original") {
5358 this.instance.currentItem.css({ top: "auto", left: "auto" });
5359 }
5360
5361 } else {
5362 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
5363 this.instance._trigger("deactivate", event, uiSortable);
5364 }
5365
5366 });
5367
5368 },
5369 drag: function(event, ui) {
5370
5371 var inst = $(this).data("ui-draggable"), that = this;
5372
5373 $.each(inst.sortables, function() {
5374
5375 var innermostIntersecting = false,
5376 thisSortable = this;
5377
5378 //Copy over some variables to allow calling the sortable's native _intersectsWith
5379 this.instance.positionAbs = inst.positionAbs;
5380 this.instance.helperProportions = inst.helperProportions;
5381 this.instance.offset.click = inst.offset.click;
5382
5383 if(this.instance._intersectsWith(this.instance.containerCache)) {
5384 innermostIntersecting = true;
5385 $.each(inst.sortables, function () {
5386 this.instance.positionAbs = inst.positionAbs;
5387 this.instance.helperProportions = inst.helperProportions;
5388 this.instance.offset.click = inst.offset.click;
5389 if (this !== thisSortable &&
5390 this.instance._intersectsWith(this.instance.containerCache) &&
5391 $.contains(thisSortable.instance.element[0], this.instance.element[0])
5392 ) {
5393 innermostIntersecting = false;
5394 }
5395 return innermostIntersecting;
5396 });
5397 }
5398
5399
5400 if(innermostIntersecting) {
5401 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
5402 if(!this.instance.isOver) {
5403
5404 this.instance.isOver = 1;
5405 //Now we fake the start of dragging for the sortable instance,
5406 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
5407 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
5408 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
5409 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
5410 this.instance.options.helper = function() { return ui.helper[0]; };
5411
5412 event.target = this.instance.currentItem[0];
5413 this.instance._mouseCapture(event, true);
5414 this.instance._mouseStart(event, true, true);
5415
5416 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
5417 this.instance.offset.click.top = inst.offset.click.top;
5418 this.instance.offset.click.left = inst.offset.click.left;
5419 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
5420 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
5421
5422 inst._trigger("toSortable", event);
5423 inst.dropped = this.instance.element; //draggable revert needs that
5424 //hack so receive/update callbacks work (mostly)
5425 inst.currentItem = inst.element;
5426 this.instance.fromOutside = inst;
5427
5428 }
5429
5430 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
5431 if(this.instance.currentItem) {
5432 this.instance._mouseDrag(event);
5433 }
5434
5435 } else {
5436
5437 //If it doesn't intersect with the sortable, and it intersected before,
5438 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
5439 if(this.instance.isOver) {
5440
5441 this.instance.isOver = 0;
5442 this.instance.cancelHelperRemoval = true;
5443
5444 //Prevent reverting on this forced stop
5445 this.instance.options.revert = false;
5446
5447 // The out event needs to be triggered independently
5448 this.instance._trigger("out", event, this.instance._uiHash(this.instance));
5449
5450 this.instance._mouseStop(event, true);
5451 this.instance.options.helper = this.instance.options._helper;
5452
5453 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
5454 this.instance.currentItem.remove();
5455 if(this.instance.placeholder) {
5456 this.instance.placeholder.remove();
5457 }
5458
5459 inst._trigger("fromSortable", event);
5460 inst.dropped = false; //draggable revert needs that
5461 }
5462
5463 }
5464
5465 });
5466
5467 }
5468 });
5469
5470 $.ui.plugin.add("draggable", "cursor", {
5471 start: function() {
5472 var t = $("body"), o = $(this).data("ui-draggable").options;
5473 if (t.css("cursor")) {
5474 o._cursor = t.css("cursor");
5475 }
5476 t.css("cursor", o.cursor);
5477 },
5478 stop: function() {
5479 var o = $(this).data("ui-draggable").options;
5480 if (o._cursor) {
5481 $("body").css("cursor", o._cursor);
5482 }
5483 }
5484 });
5485
5486 $.ui.plugin.add("draggable", "opacity", {
5487 start: function(event, ui) {
5488 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
5489 if(t.css("opacity")) {
5490 o._opacity = t.css("opacity");
5491 }
5492 t.css("opacity", o.opacity);
5493 },
5494 stop: function(event, ui) {
5495 var o = $(this).data("ui-draggable").options;
5496 if(o._opacity) {
5497 $(ui.helper).css("opacity", o._opacity);
5498 }
5499 }
5500 });
5501
5502 $.ui.plugin.add("draggable", "scroll", {
5503 start: function() {
5504 var i = $(this).data("ui-draggable");
5505 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
5506 i.overflowOffset = i.scrollParent.offset();
5507 }
5508 },
5509 drag: function( event ) {
5510
5511 var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
5512
5513 if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
5514
5515 if(!o.axis || o.axis !== "x") {
5516 if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
5517 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
5518 } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
5519 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
5520 }
5521 }
5522
5523 if(!o.axis || o.axis !== "y") {
5524 if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
5525 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
5526 } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
5527 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
5528 }
5529 }
5530
5531 } else {
5532
5533 if(!o.axis || o.axis !== "x") {
5534 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
5535 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
5536 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
5537 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
5538 }
5539 }
5540
5541 if(!o.axis || o.axis !== "y") {
5542 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
5543 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
5544 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
5545 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
5546 }
5547 }
5548
5549 }
5550
5551 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
5552 $.ui.ddmanager.prepareOffsets(i, event);
5553 }
5554
5555 }
5556 });
5557
5558 $.ui.plugin.add("draggable", "snap", {
5559 start: function() {
5560
5561 var i = $(this).data("ui-draggable"),
5562 o = i.options;
5563
5564 i.snapElements = [];
5565
5566 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
5567 var $t = $(this),
5568 $o = $t.offset();
5569 if(this !== i.element[0]) {
5570 i.snapElements.push({
5571 item: this,
5572 width: $t.outerWidth(), height: $t.outerHeight(),
5573 top: $o.top, left: $o.left
5574 });
5575 }
5576 });
5577
5578 },
5579 drag: function(event, ui) {
5580
5581 var ts, bs, ls, rs, l, r, t, b, i, first,
5582 inst = $(this).data("ui-draggable"),
5583 o = inst.options,
5584 d = o.snapTolerance,
5585 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
5586 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
5587
5588 for (i = inst.snapElements.length - 1; i >= 0; i--){
5589
5590 l = inst.snapElements[i].left;
5591 r = l + inst.snapElements[i].width;
5592 t = inst.snapElements[i].top;
5593 b = t + inst.snapElements[i].height;
5594
5595 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
5596 if(inst.snapElements[i].snapping) {
5597 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
5598 }
5599 inst.snapElements[i].snapping = false;
5600 continue;
5601 }
5602
5603 if(o.snapMode !== "inner") {
5604 ts = Math.abs(t - y2) <= d;
5605 bs = Math.abs(b - y1) <= d;
5606 ls = Math.abs(l - x2) <= d;
5607 rs = Math.abs(r - x1) <= d;
5608 if(ts) {
5609 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
5610 }
5611 if(bs) {
5612 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
5613 }
5614 if(ls) {
5615 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
5616 }
5617 if(rs) {
5618 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
5619 }
5620 }
5621
5622 first = (ts || bs || ls || rs);
5623
5624 if(o.snapMode !== "outer") {
5625 ts = Math.abs(t - y1) <= d;
5626 bs = Math.abs(b - y2) <= d;
5627 ls = Math.abs(l - x1) <= d;
5628 rs = Math.abs(r - x2) <= d;
5629 if(ts) {
5630 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
5631 }
5632 if(bs) {
5633 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
5634 }
5635 if(ls) {
5636 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
5637 }
5638 if(rs) {
5639 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
5640 }
5641 }
5642
5643 if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
5644 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
5645 }
5646 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
5647
5648 }
5649
5650 }
5651 });
5652
5653 $.ui.plugin.add("draggable", "stack", {
5654 start: function() {
5655 var min,
5656 o = this.data("ui-draggable").options,
5657 group = $.makeArray($(o.stack)).sort(function(a,b) {
5658 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
5659 });
5660
5661 if (!group.length) { return; }
5662
5663 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
5664 $(group).each(function(i) {
5665 $(this).css("zIndex", min + i);
5666 });
5667 this.css("zIndex", (min + group.length));
5668 }
5669 });
5670
5671 $.ui.plugin.add("draggable", "zIndex", {
5672 start: function(event, ui) {
5673 var t = $(ui.helper), o = $(this).data("ui-draggable").options;
5674 if(t.css("zIndex")) {
5675 o._zIndex = t.css("zIndex");
5676 }
5677 t.css("zIndex", o.zIndex);
5678 },
5679 stop: function(event, ui) {
5680 var o = $(this).data("ui-draggable").options;
5681 if(o._zIndex) {
5682 $(ui.helper).css("zIndex", o._zIndex);
5683 }
5684 }
5685 });
5686
5687 })(jQuery);
5688 (function( $, undefined ) {
5689
5690 function isOverAxis( x, reference, size ) {
5691 return ( x > reference ) && ( x < ( reference + size ) );
5692 }
5693
5694 $.widget("ui.droppable", {
5695 version: "1.10.3",
5696 widgetEventPrefix: "drop",
5697 options: {
5698 accept: "*",
5699 activeClass: false,
5700 addClasses: true,
5701 greedy: false,
5702 hoverClass: false,
5703 scope: "default",
5704 tolerance: "intersect",
5705
5706 // callbacks
5707 activate: null,
5708 deactivate: null,
5709 drop: null,
5710 out: null,
5711 over: null
5712 },
5713 _create: function() {
5714
5715 var o = this.options,
5716 accept = o.accept;
5717
5718 this.isover = false;
5719 this.isout = true;
5720
5721 this.accept = $.isFunction(accept) ? accept : function(d) {
5722 return d.is(accept);
5723 };
5724
5725 //Store the droppable's proportions
5726 this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
5727
5728 // Add the reference and positions to the manager
5729 $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
5730 $.ui.ddmanager.droppables[o.scope].push(this);
5731
5732 (o.addClasses && this.element.addClass("ui-droppable"));
5733
5734 },
5735
5736 _destroy: function() {
5737 var i = 0,
5738 drop = $.ui.ddmanager.droppables[this.options.scope];
5739
5740 for ( ; i < drop.length; i++ ) {
5741 if ( drop[i] === this ) {
5742 drop.splice(i, 1);
5743 }
5744 }
5745
5746 this.element.removeClass("ui-droppable ui-droppable-disabled");
5747 },
5748
5749 _setOption: function(key, value) {
5750
5751 if(key === "accept") {
5752 this.accept = $.isFunction(value) ? value : function(d) {
5753 return d.is(value);
5754 };
5755 }
5756 $.Widget.prototype._setOption.apply(this, arguments);
5757 },
5758
5759 _activate: function(event) {
5760 var draggable = $.ui.ddmanager.current;
5761 if(this.options.activeClass) {
5762 this.element.addClass(this.options.activeClass);
5763 }
5764 if(draggable){
5765 this._trigger("activate", event, this.ui(draggable));
5766 }
5767 },
5768
5769 _deactivate: function(event) {
5770 var draggable = $.ui.ddmanager.current;
5771 if(this.options.activeClass) {
5772 this.element.removeClass(this.options.activeClass);
5773 }
5774 if(draggable){
5775 this._trigger("deactivate", event, this.ui(draggable));
5776 }
5777 },
5778
5779 _over: function(event) {
5780
5781 var draggable = $.ui.ddmanager.current;
5782
5783 // Bail if draggable and droppable are same element
5784 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
5785 return;
5786 }
5787
5788 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
5789 if(this.options.hoverClass) {
5790 this.element.addClass(this.options.hoverClass);
5791 }
5792 this._trigger("over", event, this.ui(draggable));
5793 }
5794
5795 },
5796
5797 _out: function(event) {
5798
5799 var draggable = $.ui.ddmanager.current;
5800
5801 // Bail if draggable and droppable are same element
5802 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
5803 return;
5804 }
5805
5806 if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
5807 if(this.options.hoverClass) {
5808 this.element.removeClass(this.options.hoverClass);
5809 }
5810 this._trigger("out", event, this.ui(draggable));
5811 }
5812
5813 },
5814
5815 _drop: function(event,custom) {
5816
5817 var draggable = custom || $.ui.ddmanager.current,
5818 childrenIntersection = false;
5819
5820 // Bail if draggable and droppable are same element
5821 if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
5822 return false;
5823 }
5824
5825 this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
5826 var inst = $.data(this, "ui-droppable");
5827 if(
5828 inst.options.greedy &&
5829 !inst.options.disabled &&
5830 inst.options.scope === draggable.options.scope &&
5831 inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
5832 $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
5833 ) { childrenIntersection = true; return false; }
5834 });
5835 if(childrenIntersection) {
5836 return false;
5837 }
5838
5839 if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
5840 if(this.options.activeClass) {
5841 this.element.removeClass(this.options.activeClass);
5842 }
5843 if(this.options.hoverClass) {
5844 this.element.removeClass(this.options.hoverClass);
5845 }
5846 this._trigger("drop", event, this.ui(draggable));
5847 return this.element;
5848 }
5849
5850 return false;
5851
5852 },
5853
5854 ui: function(c) {
5855 return {
5856 draggable: (c.currentItem || c.element),
5857 helper: c.helper,
5858 position: c.position,
5859 offset: c.positionAbs
5860 };
5861 }
5862
5863 });
5864
5865 $.ui.intersect = function(draggable, droppable, toleranceMode) {
5866
5867 if (!droppable.offset) {
5868 return false;
5869 }
5870
5871 var draggableLeft, draggableTop,
5872 x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
5873 y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
5874 l = droppable.offset.left, r = l + droppable.proportions.width,
5875 t = droppable.offset.top, b = t + droppable.proportions.height;
5876
5877 switch (toleranceMode) {
5878 case "fit":
5879 return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
5880 case "intersect":
5881 return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
5882 x2 - (draggable.helperProportions.width / 2) < r && // Left Half
5883 t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
5884 y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
5885 case "pointer":
5886 draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
5887 draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
5888 return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
5889 case "touch":
5890 return (
5891 (y1 >= t && y1 <= b) || // Top edge touching
5892 (y2 >= t && y2 <= b) || // Bottom edge touching
5893 (y1 < t && y2 > b) // Surrounded vertically
5894 ) && (
5895 (x1 >= l && x1 <= r) || // Left edge touching
5896 (x2 >= l && x2 <= r) || // Right edge touching
5897 (x1 < l && x2 > r) // Surrounded horizontally
5898 );
5899 default:
5900 return false;
5901 }
5902
5903 };
5904
5905 /*
5906 This manager tracks offsets of draggables and droppables
5907 */
5908 $.ui.ddmanager = {
5909 current: null,
5910 droppables: { "default": [] },
5911 prepareOffsets: function(t, event) {
5912
5913 var i, j,
5914 m = $.ui.ddmanager.droppables[t.options.scope] || [],
5915 type = event ? event.type : null, // workaround for #2317
5916 list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
5917
5918 droppablesLoop: for (i = 0; i < m.length; i++) {
5919
5920 //No disabled and non-accepted
5921 if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
5922 continue;
5923 }
5924
5925 // Filter out elements in the current dragged item
5926 for (j=0; j < list.length; j++) {
5927 if(list[j] === m[i].element[0]) {
5928 m[i].proportions.height = 0;
5929 continue droppablesLoop;
5930 }
5931 }
5932
5933 m[i].visible = m[i].element.css("display") !== "none";
5934 if(!m[i].visible) {
5935 continue;
5936 }
5937
5938 //Activate the droppable if used directly from draggables
5939 if(type === "mousedown") {
5940 m[i]._activate.call(m[i], event);
5941 }
5942
5943 m[i].offset = m[i].element.offset();
5944 m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
5945
5946 }
5947
5948 },
5949 drop: function(draggable, event) {
5950
5951 var dropped = false;
5952 // Create a copy of the droppables in case the list changes during the drop (#9116)
5953 $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
5954
5955 if(!this.options) {
5956 return;
5957 }
5958 if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
5959 dropped = this._drop.call(this, event) || dropped;
5960 }
5961
5962 if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
5963 this.isout = true;
5964 this.isover = false;
5965 this._deactivate.call(this, event);
5966 }
5967
5968 });
5969 return dropped;
5970
5971 },
5972 dragStart: function( draggable, event ) {
5973 //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
5974 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
5975 if( !draggable.options.refreshPositions ) {
5976 $.ui.ddmanager.prepareOffsets( draggable, event );
5977 }
5978 });
5979 },
5980 drag: function(draggable, event) {
5981
5982 //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
5983 if(draggable.options.refreshPositions) {
5984 $.ui.ddmanager.prepareOffsets(draggable, event);
5985 }
5986
5987 //Run through all droppables and check their positions based on specific tolerance options
5988 $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
5989
5990 if(this.options.disabled || this.greedyChild || !this.visible) {
5991 return;
5992 }
5993
5994 var parentInstance, scope, parent,
5995 intersects = $.ui.intersect(draggable, this, this.options.tolerance),
5996 c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
5997 if(!c) {
5998 return;
5999 }
6000
6001 if (this.options.greedy) {
6002 // find droppable parents with same scope
6003 scope = this.options.scope;
6004 parent = this.element.parents(":data(ui-droppable)").filter(function () {
6005 return $.data(this, "ui-droppable").options.scope === scope;
6006 });
6007
6008 if (parent.length) {
6009 parentInstance = $.data(parent[0], "ui-droppable");
6010 parentInstance.greedyChild = (c === "isover");
6011 }
6012 }
6013
6014 // we just moved into a greedy child
6015 if (parentInstance && c === "isover") {
6016 parentInstance.isover = false;
6017 parentInstance.isout = true;
6018 parentInstance._out.call(parentInstance, event);
6019 }
6020
6021 this[c] = true;
6022 this[c === "isout" ? "isover" : "isout"] = false;
6023 this[c === "isover" ? "_over" : "_out"].call(this, event);
6024
6025 // we just moved out of a greedy child
6026 if (parentInstance && c === "isout") {
6027 parentInstance.isout = false;
6028 parentInstance.isover = true;
6029 parentInstance._over.call(parentInstance, event);
6030 }
6031 });
6032
6033 },
6034 dragStop: function( draggable, event ) {
6035 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
6036 //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
6037 if( !draggable.options.refreshPositions ) {
6038 $.ui.ddmanager.prepareOffsets( draggable, event );
6039 }
6040 }
6041 };
6042
6043 })(jQuery);
6044 (function( $, undefined ) {
6045
6046 function num(v) {
6047 return parseInt(v, 10) || 0;
6048 }
6049
6050 function isNumber(value) {
6051 return !isNaN(parseInt(value, 10));
6052 }
6053
6054 $.widget("ui.resizable", $.ui.mouse, {
6055 version: "1.10.3",
6056 widgetEventPrefix: "resize",
6057 options: {
6058 alsoResize: false,
6059 animate: false,
6060 animateDuration: "slow",
6061 animateEasing: "swing",
6062 aspectRatio: false,
6063 autoHide: false,
6064 containment: false,
6065 ghost: false,
6066 grid: false,
6067 handles: "e,s,se",
6068 helper: false,
6069 maxHeight: null,
6070 maxWidth: null,
6071 minHeight: 10,
6072 minWidth: 10,
6073 // See #7960
6074 zIndex: 90,
6075
6076 // callbacks
6077 resize: null,
6078 start: null,
6079 stop: null
6080 },
6081 _create: function() {
6082
6083 var n, i, handle, axis, hname,
6084 that = this,
6085 o = this.options;
6086 this.element.addClass("ui-resizable");
6087
6088 $.extend(this, {
6089 _aspectRatio: !!(o.aspectRatio),
6090 aspectRatio: o.aspectRatio,
6091 originalElement: this.element,
6092 _proportionallyResizeElements: [],
6093 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
6094 });
6095
6096 //Wrap the element if it cannot hold child nodes
6097 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
6098
6099 //Create a wrapper element and set the wrapper to the new current internal element
6100 this.element.wrap(
6101 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
6102 position: this.element.css("position"),
6103 width: this.element.outerWidth(),
6104 height: this.element.outerHeight(),
6105 top: this.element.css("top"),
6106 left: this.element.css("left")
6107 })
6108 );
6109
6110 //Overwrite the original this.element
6111 this.element = this.element.parent().data(
6112 "ui-resizable", this.element.data("ui-resizable")
6113 );
6114
6115 this.elementIsWrapper = true;
6116
6117 //Move margins to the wrapper
6118 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
6119 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
6120
6121 //Prevent Safari textarea resize
6122 this.originalResizeStyle = this.originalElement.css("resize");
6123 this.originalElement.css("resize", "none");
6124
6125 //Push the actual element to our proportionallyResize internal array
6126 this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
6127
6128 // avoid IE jump (hard set the margin)
6129 this.originalElement.css({ margin: this.originalElement.css("margin") });
6130
6131 // fix handlers offset
6132 this._proportionallyResize();
6133
6134 }
6135
6136 this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
6137 if(this.handles.constructor === String) {
6138
6139 if ( this.handles === "all") {
6140 this.handles = "n,e,s,w,se,sw,ne,nw";
6141 }
6142
6143 n = this.handles.split(",");
6144 this.handles = {};
6145
6146 for(i = 0; i < n.length; i++) {
6147
6148 handle = $.trim(n[i]);
6149 hname = "ui-resizable-"+handle;
6150 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
6151
6152 // Apply zIndex to all handles - see #7960
6153 axis.css({ zIndex: o.zIndex });
6154
6155 //TODO : What's going on here?
6156 if ("se" === handle) {
6157 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
6158 }
6159
6160 //Insert into internal handles object and append to element
6161 this.handles[handle] = ".ui-resizable-"+handle;
6162 this.element.append(axis);
6163 }
6164
6165 }
6166
6167 this._renderAxis = function(target) {
6168
6169 var i, axis, padPos, padWrapper;
6170
6171 target = target || this.element;
6172
6173 for(i in this.handles) {
6174
6175 if(this.handles[i].constructor === String) {
6176 this.handles[i] = $(this.handles[i], this.element).show();
6177 }
6178
6179 //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
6180 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
6181
6182 axis = $(this.handles[i], this.element);
6183
6184 //Checking the correct pad and border
6185 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
6186
6187 //The padding type i have to apply...
6188 padPos = [ "padding",
6189 /ne|nw|n/.test(i) ? "Top" :
6190 /se|sw|s/.test(i) ? "Bottom" :
6191 /^e$/.test(i) ? "Right" : "Left" ].join("");
6192
6193 target.css(padPos, padWrapper);
6194
6195 this._proportionallyResize();
6196
6197 }
6198
6199 //TODO: What's that good for? There's not anything to be executed left
6200 if(!$(this.handles[i]).length) {
6201 continue;
6202 }
6203 }
6204 };
6205
6206 //TODO: make renderAxis a prototype function
6207 this._renderAxis(this.element);
6208
6209 this._handles = $(".ui-resizable-handle", this.element)
6210 .disableSelection();
6211
6212 //Matching axis name
6213 this._handles.mouseover(function() {
6214 if (!that.resizing) {
6215 if (this.className) {
6216 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
6217 }
6218 //Axis, default = se
6219 that.axis = axis && axis[1] ? axis[1] : "se";
6220 }
6221 });
6222
6223 //If we want to auto hide the elements
6224 if (o.autoHide) {
6225 this._handles.hide();
6226 $(this.element)
6227 .addClass("ui-resizable-autohide")
6228 .mouseenter(function() {
6229 if (o.disabled) {
6230 return;
6231 }
6232 $(this).removeClass("ui-resizable-autohide");
6233 that._handles.show();
6234 })
6235 .mouseleave(function(){
6236 if (o.disabled) {
6237 return;
6238 }
6239 if (!that.resizing) {
6240 $(this).addClass("ui-resizable-autohide");
6241 that._handles.hide();
6242 }
6243 });
6244 }
6245
6246 //Initialize the mouse interaction
6247 this._mouseInit();
6248
6249 },
6250
6251 _destroy: function() {
6252
6253 this._mouseDestroy();
6254
6255 var wrapper,
6256 _destroy = function(exp) {
6257 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
6258 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
6259 };
6260
6261 //TODO: Unwrap at same DOM position
6262 if (this.elementIsWrapper) {
6263 _destroy(this.element);
6264 wrapper = this.element;
6265 this.originalElement.css({
6266 position: wrapper.css("position"),
6267 width: wrapper.outerWidth(),
6268 height: wrapper.outerHeight(),
6269 top: wrapper.css("top"),
6270 left: wrapper.css("left")
6271 }).insertAfter( wrapper );
6272 wrapper.remove();
6273 }
6274
6275 this.originalElement.css("resize", this.originalResizeStyle);
6276 _destroy(this.originalElement);
6277
6278 return this;
6279 },
6280
6281 _mouseCapture: function(event) {
6282 var i, handle,
6283 capture = false;
6284
6285 for (i in this.handles) {
6286 handle = $(this.handles[i])[0];
6287 if (handle === event.target || $.contains(handle, event.target)) {
6288 capture = true;
6289 }
6290 }
6291
6292 return !this.options.disabled && capture;
6293 },
6294
6295 _mouseStart: function(event) {
6296
6297 var curleft, curtop, cursor,
6298 o = this.options,
6299 iniPos = this.element.position(),
6300 el = this.element;
6301
6302 this.resizing = true;
6303
6304 // bugfix for http://dev.jquery.com/ticket/1749
6305 if ( (/absolute/).test( el.css("position") ) ) {
6306 el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
6307 } else if (el.is(".ui-draggable")) {
6308 el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
6309 }
6310
6311 this._renderProxy();
6312
6313 curleft = num(this.helper.css("left"));
6314 curtop = num(this.helper.css("top"));
6315
6316 if (o.containment) {
6317 curleft += $(o.containment).scrollLeft() || 0;
6318 curtop += $(o.containment).scrollTop() || 0;
6319 }
6320
6321 //Store needed variables
6322 this.offset = this.helper.offset();
6323 this.position = { left: curleft, top: curtop };
6324 this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
6325 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
6326 this.originalPosition = { left: curleft, top: curtop };
6327 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
6328 this.originalMousePosition = { left: event.pageX, top: event.pageY };
6329
6330 //Aspect Ratio
6331 this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
6332
6333 cursor = $(".ui-resizable-" + this.axis).css("cursor");
6334 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
6335
6336 el.addClass("ui-resizable-resizing");
6337 this._propagate("start", event);
6338 return true;
6339 },
6340
6341 _mouseDrag: function(event) {
6342
6343 //Increase performance, avoid regex
6344 var data,
6345 el = this.helper, props = {},
6346 smp = this.originalMousePosition,
6347 a = this.axis,
6348 prevTop = this.position.top,
6349 prevLeft = this.position.left,
6350 prevWidth = this.size.width,
6351 prevHeight = this.size.height,
6352 dx = (event.pageX-smp.left)||0,
6353 dy = (event.pageY-smp.top)||0,
6354 trigger = this._change[a];
6355
6356 if (!trigger) {
6357 return false;
6358 }
6359
6360 // Calculate the attrs that will be change
6361 data = trigger.apply(this, [event, dx, dy]);
6362
6363 // Put this in the mouseDrag handler since the user can start pressing shift while resizing
6364 this._updateVirtualBoundaries(event.shiftKey);
6365 if (this._aspectRatio || event.shiftKey) {
6366 data = this._updateRatio(data, event);
6367 }
6368
6369 data = this._respectSize(data, event);
6370
6371 this._updateCache(data);
6372
6373 // plugins callbacks need to be called first
6374 this._propagate("resize", event);
6375
6376 if (this.position.top !== prevTop) {
6377 props.top = this.position.top + "px";
6378 }
6379 if (this.position.left !== prevLeft) {
6380 props.left = this.position.left + "px";
6381 }
6382 if (this.size.width !== prevWidth) {
6383 props.width = this.size.width + "px";
6384 }
6385 if (this.size.height !== prevHeight) {
6386 props.height = this.size.height + "px";
6387 }
6388 el.css(props);
6389
6390 if (!this._helper && this._proportionallyResizeElements.length) {
6391 this._proportionallyResize();
6392 }
6393
6394 // Call the user callback if the element was resized
6395 if ( ! $.isEmptyObject(props) ) {
6396 this._trigger("resize", event, this.ui());
6397 }
6398
6399 return false;
6400 },
6401
6402 _mouseStop: function(event) {
6403
6404 this.resizing = false;
6405 var pr, ista, soffseth, soffsetw, s, left, top,
6406 o = this.options, that = this;
6407
6408 if(this._helper) {
6409
6410 pr = this._proportionallyResizeElements;
6411 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
6412 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
6413 soffsetw = ista ? 0 : that.sizeDiff.width;
6414
6415 s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
6416 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
6417 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
6418
6419 if (!o.animate) {
6420 this.element.css($.extend(s, { top: top, left: left }));
6421 }
6422
6423 that.helper.height(that.size.height);
6424 that.helper.width(that.size.width);
6425
6426 if (this._helper && !o.animate) {
6427 this._proportionallyResize();
6428 }
6429 }
6430
6431 $("body").css("cursor", "auto");
6432
6433 this.element.removeClass("ui-resizable-resizing");
6434
6435 this._propagate("stop", event);
6436
6437 if (this._helper) {
6438 this.helper.remove();
6439 }
6440
6441 return false;
6442
6443 },
6444
6445 _updateVirtualBoundaries: function(forceAspectRatio) {
6446 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
6447 o = this.options;
6448
6449 b = {
6450 minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
6451 maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
6452 minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
6453 maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
6454 };
6455
6456 if(this._aspectRatio || forceAspectRatio) {
6457 // We want to create an enclosing box whose aspect ration is the requested one
6458 // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
6459 pMinWidth = b.minHeight * this.aspectRatio;
6460 pMinHeight = b.minWidth / this.aspectRatio;
6461 pMaxWidth = b.maxHeight * this.aspectRatio;
6462 pMaxHeight = b.maxWidth / this.aspectRatio;
6463
6464 if(pMinWidth > b.minWidth) {
6465 b.minWidth = pMinWidth;
6466 }
6467 if(pMinHeight > b.minHeight) {
6468 b.minHeight = pMinHeight;
6469 }
6470 if(pMaxWidth < b.maxWidth) {
6471 b.maxWidth = pMaxWidth;
6472 }
6473 if(pMaxHeight < b.maxHeight) {
6474 b.maxHeight = pMaxHeight;
6475 }
6476 }
6477 this._vBoundaries = b;
6478 },
6479
6480 _updateCache: function(data) {
6481 this.offset = this.helper.offset();
6482 if (isNumber(data.left)) {
6483 this.position.left = data.left;
6484 }
6485 if (isNumber(data.top)) {
6486 this.position.top = data.top;
6487 }
6488 if (isNumber(data.height)) {
6489 this.size.height = data.height;
6490 }
6491 if (isNumber(data.width)) {
6492 this.size.width = data.width;
6493 }
6494 },
6495
6496 _updateRatio: function( data ) {
6497
6498 var cpos = this.position,
6499 csize = this.size,
6500 a = this.axis;
6501
6502 if (isNumber(data.height)) {
6503 data.width = (data.height * this.aspectRatio);
6504 } else if (isNumber(data.width)) {
6505 data.height = (data.width / this.aspectRatio);
6506 }
6507
6508 if (a === "sw") {
6509 data.left = cpos.left + (csize.width - data.width);
6510 data.top = null;
6511 }
6512 if (a === "nw") {
6513 data.top = cpos.top + (csize.height - data.height);
6514 data.left = cpos.left + (csize.width - data.width);
6515 }
6516
6517 return data;
6518 },
6519
6520 _respectSize: function( data ) {
6521
6522 var o = this._vBoundaries,
6523 a = this.axis,
6524 ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
6525 isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
6526 dw = this.originalPosition.left + this.originalSize.width,
6527 dh = this.position.top + this.size.height,
6528 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
6529 if (isminw) {
6530 data.width = o.minWidth;
6531 }
6532 if (isminh) {
6533 data.height = o.minHeight;
6534 }
6535 if (ismaxw) {
6536 data.width = o.maxWidth;
6537 }
6538 if (ismaxh) {
6539 data.height = o.maxHeight;
6540 }
6541
6542 if (isminw && cw) {
6543 data.left = dw - o.minWidth;
6544 }
6545 if (ismaxw && cw) {
6546 data.left = dw - o.maxWidth;
6547 }
6548 if (isminh && ch) {
6549 data.top = dh - o.minHeight;
6550 }
6551 if (ismaxh && ch) {
6552 data.top = dh - o.maxHeight;
6553 }
6554
6555 // fixing jump error on top/left - bug #2330
6556 if (!data.width && !data.height && !data.left && data.top) {
6557 data.top = null;
6558 } else if (!data.width && !data.height && !data.top && data.left) {
6559 data.left = null;
6560 }
6561
6562 return data;
6563 },
6564
6565 _proportionallyResize: function() {
6566
6567 if (!this._proportionallyResizeElements.length) {
6568 return;
6569 }
6570
6571 var i, j, borders, paddings, prel,
6572 element = this.helper || this.element;
6573
6574 for ( i=0; i < this._proportionallyResizeElements.length; i++) {
6575
6576 prel = this._proportionallyResizeElements[i];
6577
6578 if (!this.borderDif) {
6579 this.borderDif = [];
6580 borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
6581 paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
6582
6583 for ( j = 0; j < borders.length; j++ ) {
6584 this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
6585 }
6586 }
6587
6588 prel.css({
6589 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
6590 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
6591 });
6592
6593 }
6594
6595 },
6596
6597 _renderProxy: function() {
6598
6599 var el = this.element, o = this.options;
6600 this.elementOffset = el.offset();
6601
6602 if(this._helper) {
6603
6604 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
6605
6606 this.helper.addClass(this._helper).css({
6607 width: this.element.outerWidth() - 1,
6608 height: this.element.outerHeight() - 1,
6609 position: "absolute",
6610 left: this.elementOffset.left +"px",
6611 top: this.elementOffset.top +"px",
6612 zIndex: ++o.zIndex //TODO: Don't modify option
6613 });
6614
6615 this.helper
6616 .appendTo("body")
6617 .disableSelection();
6618
6619 } else {
6620 this.helper = this.element;
6621 }
6622
6623 },
6624
6625 _change: {
6626 e: function(event, dx) {
6627 return { width: this.originalSize.width + dx };
6628 },
6629 w: function(event, dx) {
6630 var cs = this.originalSize, sp = this.originalPosition;
6631 return { left: sp.left + dx, width: cs.width - dx };
6632 },
6633 n: function(event, dx, dy) {
6634 var cs = this.originalSize, sp = this.originalPosition;
6635 return { top: sp.top + dy, height: cs.height - dy };
6636 },
6637 s: function(event, dx, dy) {
6638 return { height: this.originalSize.height + dy };
6639 },
6640 se: function(event, dx, dy) {
6641 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
6642 },
6643 sw: function(event, dx, dy) {
6644 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
6645 },
6646 ne: function(event, dx, dy) {
6647 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
6648 },
6649 nw: function(event, dx, dy) {
6650 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
6651 }
6652 },
6653
6654 _propagate: function(n, event) {
6655 $.ui.plugin.call(this, n, [event, this.ui()]);
6656 (n !== "resize" && this._trigger(n, event, this.ui()));
6657 },
6658
6659 plugins: {},
6660
6661 ui: function() {
6662 return {
6663 originalElement: this.originalElement,
6664 element: this.element,
6665 helper: this.helper,
6666 position: this.position,
6667 size: this.size,
6668 originalSize: this.originalSize,
6669 originalPosition: this.originalPosition
6670 };
6671 }
6672
6673 });
6674
6675 /*
6676 * Resizable Extensions
6677 */
6678
6679 $.ui.plugin.add("resizable", "animate", {
6680
6681 stop: function( event ) {
6682 var that = $(this).data("ui-resizable"),
6683 o = that.options,
6684 pr = that._proportionallyResizeElements,
6685 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
6686 soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
6687 soffsetw = ista ? 0 : that.sizeDiff.width,
6688 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
6689 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
6690 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
6691
6692 that.element.animate(
6693 $.extend(style, top && left ? { top: top, left: left } : {}), {
6694 duration: o.animateDuration,
6695 easing: o.animateEasing,
6696 step: function() {
6697
6698 var data = {
6699 width: parseInt(that.element.css("width"), 10),
6700 height: parseInt(that.element.css("height"), 10),
6701 top: parseInt(that.element.css("top"), 10),
6702 left: parseInt(that.element.css("left"), 10)
6703 };
6704
6705 if (pr && pr.length) {
6706 $(pr[0]).css({ width: data.width, height: data.height });
6707 }
6708
6709 // propagating resize, and updating values for each animation step
6710 that._updateCache(data);
6711 that._propagate("resize", event);
6712
6713 }
6714 }
6715 );
6716 }
6717
6718 });
6719
6720 $.ui.plugin.add("resizable", "containment", {
6721
6722 start: function() {
6723 var element, p, co, ch, cw, width, height,
6724 that = $(this).data("ui-resizable"),
6725 o = that.options,
6726 el = that.element,
6727 oc = o.containment,
6728 ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
6729
6730 if (!ce) {
6731 return;
6732 }
6733
6734 that.containerElement = $(ce);
6735
6736 if (/document/.test(oc) || oc === document) {
6737 that.containerOffset = { left: 0, top: 0 };
6738 that.containerPosition = { left: 0, top: 0 };
6739
6740 that.parentData = {
6741 element: $(document), left: 0, top: 0,
6742 width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
6743 };
6744 }
6745
6746 // i'm a node, so compute top, left, right, bottom
6747 else {
6748 element = $(ce);
6749 p = [];
6750 $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
6751
6752 that.containerOffset = element.offset();
6753 that.containerPosition = element.position();
6754 that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
6755
6756 co = that.containerOffset;
6757 ch = that.containerSize.height;
6758 cw = that.containerSize.width;
6759 width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
6760 height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
6761
6762 that.parentData = {
6763 element: ce, left: co.left, top: co.top, width: width, height: height
6764 };
6765 }
6766 },
6767
6768 resize: function( event ) {
6769 var woset, hoset, isParent, isOffsetRelative,
6770 that = $(this).data("ui-resizable"),
6771 o = that.options,
6772 co = that.containerOffset, cp = that.position,
6773 pRatio = that._aspectRatio || event.shiftKey,
6774 cop = { top:0, left:0 }, ce = that.containerElement;
6775
6776 if (ce[0] !== document && (/static/).test(ce.css("position"))) {
6777 cop = co;
6778 }
6779
6780 if (cp.left < (that._helper ? co.left : 0)) {
6781 that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
6782 if (pRatio) {
6783 that.size.height = that.size.width / that.aspectRatio;
6784 }
6785 that.position.left = o.helper ? co.left : 0;
6786 }
6787
6788 if (cp.top < (that._helper ? co.top : 0)) {
6789 that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
6790 if (pRatio) {
6791 that.size.width = that.size.height * that.aspectRatio;
6792 }
6793 that.position.top = that._helper ? co.top : 0;
6794 }
6795
6796 that.offset.left = that.parentData.left+that.position.left;
6797 that.offset.top = that.parentData.top+that.position.top;
6798
6799 woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
6800 hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
6801
6802 isParent = that.containerElement.get(0) === that.element.parent().get(0);
6803 isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
6804
6805 if(isParent && isOffsetRelative) {
6806 woset -= that.parentData.left;
6807 }
6808
6809 if (woset + that.size.width >= that.parentData.width) {
6810 that.size.width = that.parentData.width - woset;
6811 if (pRatio) {
6812 that.size.height = that.size.width / that.aspectRatio;
6813 }
6814 }
6815
6816 if (hoset + that.size.height >= that.parentData.height) {
6817 that.size.height = that.parentData.height - hoset;
6818 if (pRatio) {
6819 that.size.width = that.size.height * that.aspectRatio;
6820 }
6821 }
6822 },
6823
6824 stop: function(){
6825 var that = $(this).data("ui-resizable"),
6826 o = that.options,
6827 co = that.containerOffset,
6828 cop = that.containerPosition,
6829 ce = that.containerElement,
6830 helper = $(that.helper),
6831 ho = helper.offset(),
6832 w = helper.outerWidth() - that.sizeDiff.width,
6833 h = helper.outerHeight() - that.sizeDiff.height;
6834
6835 if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
6836 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
6837 }
6838
6839 if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
6840 $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
6841 }
6842
6843 }
6844 });
6845
6846 $.ui.plugin.add("resizable", "alsoResize", {
6847
6848 start: function () {
6849 var that = $(this).data("ui-resizable"),
6850 o = that.options,
6851 _store = function (exp) {
6852 $(exp).each(function() {
6853 var el = $(this);
6854 el.data("ui-resizable-alsoresize", {
6855 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
6856 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
6857 });
6858 });
6859 };
6860
6861 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
6862 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
6863 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
6864 }else{
6865 _store(o.alsoResize);
6866 }
6867 },
6868
6869 resize: function (event, ui) {
6870 var that = $(this).data("ui-resizable"),
6871 o = that.options,
6872 os = that.originalSize,
6873 op = that.originalPosition,
6874 delta = {
6875 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
6876 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
6877 },
6878
6879 _alsoResize = function (exp, c) {
6880 $(exp).each(function() {
6881 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
6882 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
6883
6884 $.each(css, function (i, prop) {
6885 var sum = (start[prop]||0) + (delta[prop]||0);
6886 if (sum && sum >= 0) {
6887 style[prop] = sum || null;
6888 }
6889 });
6890
6891 el.css(style);
6892 });
6893 };
6894
6895 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
6896 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
6897 }else{
6898 _alsoResize(o.alsoResize);
6899 }
6900 },
6901
6902 stop: function () {
6903 $(this).removeData("resizable-alsoresize");
6904 }
6905 });
6906
6907 $.ui.plugin.add("resizable", "ghost", {
6908
6909 start: function() {
6910
6911 var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
6912
6913 that.ghost = that.originalElement.clone();
6914 that.ghost
6915 .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
6916 .addClass("ui-resizable-ghost")
6917 .addClass(typeof o.ghost === "string" ? o.ghost : "");
6918
6919 that.ghost.appendTo(that.helper);
6920
6921 },
6922
6923 resize: function(){
6924 var that = $(this).data("ui-resizable");
6925 if (that.ghost) {
6926 that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
6927 }
6928 },
6929
6930 stop: function() {
6931 var that = $(this).data("ui-resizable");
6932 if (that.ghost && that.helper) {
6933 that.helper.get(0).removeChild(that.ghost.get(0));
6934 }
6935 }
6936
6937 });
6938
6939 $.ui.plugin.add("resizable", "grid", {
6940
6941 resize: function() {
6942 var that = $(this).data("ui-resizable"),
6943 o = that.options,
6944 cs = that.size,
6945 os = that.originalSize,
6946 op = that.originalPosition,
6947 a = that.axis,
6948 grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
6949 gridX = (grid[0]||1),
6950 gridY = (grid[1]||1),
6951 ox = Math.round((cs.width - os.width) / gridX) * gridX,
6952 oy = Math.round((cs.height - os.height) / gridY) * gridY,
6953 newWidth = os.width + ox,
6954 newHeight = os.height + oy,
6955 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
6956 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
6957 isMinWidth = o.minWidth && (o.minWidth > newWidth),
6958 isMinHeight = o.minHeight && (o.minHeight > newHeight);
6959
6960 o.grid = grid;
6961
6962 if (isMinWidth) {
6963 newWidth = newWidth + gridX;
6964 }
6965 if (isMinHeight) {
6966 newHeight = newHeight + gridY;
6967 }
6968 if (isMaxWidth) {
6969 newWidth = newWidth - gridX;
6970 }
6971 if (isMaxHeight) {
6972 newHeight = newHeight - gridY;
6973 }
6974
6975 if (/^(se|s|e)$/.test(a)) {
6976 that.size.width = newWidth;
6977 that.size.height = newHeight;
6978 } else if (/^(ne)$/.test(a)) {
6979 that.size.width = newWidth;
6980 that.size.height = newHeight;
6981 that.position.top = op.top - oy;
6982 } else if (/^(sw)$/.test(a)) {
6983 that.size.width = newWidth;
6984 that.size.height = newHeight;
6985 that.position.left = op.left - ox;
6986 } else {
6987 that.size.width = newWidth;
6988 that.size.height = newHeight;
6989 that.position.top = op.top - oy;
6990 that.position.left = op.left - ox;
6991 }
6992 }
6993
6994 });
6995
6996 })(jQuery);
6997 (function( $, undefined ) {
6998
6999 $.widget("ui.selectable", $.ui.mouse, {
7000 version: "1.10.3",
7001 options: {
7002 appendTo: "body",
7003 autoRefresh: true,
7004 distance: 0,
7005 filter: "*",
7006 tolerance: "touch",
7007
7008 // callbacks
7009 selected: null,
7010 selecting: null,
7011 start: null,
7012 stop: null,
7013 unselected: null,
7014 unselecting: null
7015 },
7016 _create: function() {
7017 var selectees,
7018 that = this;
7019
7020 this.element.addClass("ui-selectable");
7021
7022 this.dragged = false;
7023
7024 // cache selectee children based on filter
7025 this.refresh = function() {
7026 selectees = $(that.options.filter, that.element[0]);
7027 selectees.addClass("ui-selectee");
7028 selectees.each(function() {
7029 var $this = $(this),
7030 pos = $this.offset();
7031 $.data(this, "selectable-item", {
7032 element: this,
7033 $element: $this,
7034 left: pos.left,
7035 top: pos.top,
7036 right: pos.left + $this.outerWidth(),
7037 bottom: pos.top + $this.outerHeight(),
7038 startselected: false,
7039 selected: $this.hasClass("ui-selected"),
7040 selecting: $this.hasClass("ui-selecting"),
7041 unselecting: $this.hasClass("ui-unselecting")
7042 });
7043 });
7044 };
7045 this.refresh();
7046
7047 this.selectees = selectees.addClass("ui-selectee");
7048
7049 this._mouseInit();
7050
7051 this.helper = $("<div class='ui-selectable-helper'></div>");
7052 },
7053
7054 _destroy: function() {
7055 this.selectees
7056 .removeClass("ui-selectee")
7057 .removeData("selectable-item");
7058 this.element
7059 .removeClass("ui-selectable ui-selectable-disabled");
7060 this._mouseDestroy();
7061 },
7062
7063 _mouseStart: function(event) {
7064 var that = this,
7065 options = this.options;
7066
7067 this.opos = [event.pageX, event.pageY];
7068
7069 if (this.options.disabled) {
7070 return;
7071 }
7072
7073 this.selectees = $(options.filter, this.element[0]);
7074
7075 this._trigger("start", event);
7076
7077 $(options.appendTo).append(this.helper);
7078 // position helper (lasso)
7079 this.helper.css({
7080 "left": event.pageX,
7081 "top": event.pageY,
7082 "width": 0,
7083 "height": 0
7084 });
7085
7086 if (options.autoRefresh) {
7087 this.refresh();
7088 }
7089
7090 this.selectees.filter(".ui-selected").each(function() {
7091 var selectee = $.data(this, "selectable-item");
7092 selectee.startselected = true;
7093 if (!event.metaKey && !event.ctrlKey) {
7094 selectee.$element.removeClass("ui-selected");
7095 selectee.selected = false;
7096 selectee.$element.addClass("ui-unselecting");
7097 selectee.unselecting = true;
7098 // selectable UNSELECTING callback
7099 that._trigger("unselecting", event, {
7100 unselecting: selectee.element
7101 });
7102 }
7103 });
7104
7105 $(event.target).parents().addBack().each(function() {
7106 var doSelect,
7107 selectee = $.data(this, "selectable-item");
7108 if (selectee) {
7109 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
7110 selectee.$element
7111 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
7112 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
7113 selectee.unselecting = !doSelect;
7114 selectee.selecting = doSelect;
7115 selectee.selected = doSelect;
7116 // selectable (UN)SELECTING callback
7117 if (doSelect) {
7118 that._trigger("selecting", event, {
7119 selecting: selectee.element
7120 });
7121 } else {
7122 that._trigger("unselecting", event, {
7123 unselecting: selectee.element
7124 });
7125 }
7126 return false;
7127 }
7128 });
7129
7130 },
7131
7132 _mouseDrag: function(event) {
7133
7134 this.dragged = true;
7135
7136 if (this.options.disabled) {
7137 return;
7138 }
7139
7140 var tmp,
7141 that = this,
7142 options = this.options,
7143 x1 = this.opos[0],
7144 y1 = this.opos[1],
7145 x2 = event.pageX,
7146 y2 = event.pageY;
7147
7148 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
7149 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
7150 this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
7151
7152 this.selectees.each(function() {
7153 var selectee = $.data(this, "selectable-item"),
7154 hit = false;
7155
7156 //prevent helper from being selected if appendTo: selectable
7157 if (!selectee || selectee.element === that.element[0]) {
7158 return;
7159 }
7160
7161 if (options.tolerance === "touch") {
7162 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
7163 } else if (options.tolerance === "fit") {
7164 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
7165 }
7166
7167 if (hit) {
7168 // SELECT
7169 if (selectee.selected) {
7170 selectee.$element.removeClass("ui-selected");
7171 selectee.selected = false;
7172 }
7173 if (selectee.unselecting) {
7174 selectee.$element.removeClass("ui-unselecting");
7175 selectee.unselecting = false;
7176 }
7177 if (!selectee.selecting) {
7178 selectee.$element.addClass("ui-selecting");
7179 selectee.selecting = true;
7180 // selectable SELECTING callback
7181 that._trigger("selecting", event, {
7182 selecting: selectee.element
7183 });
7184 }
7185 } else {
7186 // UNSELECT
7187 if (selectee.selecting) {
7188 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
7189 selectee.$element.removeClass("ui-selecting");
7190 selectee.selecting = false;
7191 selectee.$element.addClass("ui-selected");
7192 selectee.selected = true;
7193 } else {
7194 selectee.$element.removeClass("ui-selecting");
7195 selectee.selecting = false;
7196 if (selectee.startselected) {
7197 selectee.$element.addClass("ui-unselecting");
7198 selectee.unselecting = true;
7199 }
7200 // selectable UNSELECTING callback
7201 that._trigger("unselecting", event, {
7202 unselecting: selectee.element
7203 });
7204 }
7205 }
7206 if (selectee.selected) {
7207 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
7208 selectee.$element.removeClass("ui-selected");
7209 selectee.selected = false;
7210
7211 selectee.$element.addClass("ui-unselecting");
7212 selectee.unselecting = true;
7213 // selectable UNSELECTING callback
7214 that._trigger("unselecting", event, {
7215 unselecting: selectee.element
7216 });
7217 }
7218 }
7219 }
7220 });
7221
7222 return false;
7223 },
7224
7225 _mouseStop: function(event) {
7226 var that = this;
7227
7228 this.dragged = false;
7229
7230 $(".ui-unselecting", this.element[0]).each(function() {
7231 var selectee = $.data(this, "selectable-item");
7232 selectee.$element.removeClass("ui-unselecting");
7233 selectee.unselecting = false;
7234 selectee.startselected = false;
7235 that._trigger("unselected", event, {
7236 unselected: selectee.element
7237 });
7238 });
7239 $(".ui-selecting", this.element[0]).each(function() {
7240 var selectee = $.data(this, "selectable-item");
7241 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
7242 selectee.selecting = false;
7243 selectee.selected = true;
7244 selectee.startselected = true;
7245 that._trigger("selected", event, {
7246 selected: selectee.element
7247 });
7248 });
7249 this._trigger("stop", event);
7250
7251 this.helper.remove();
7252
7253 return false;
7254 }
7255
7256 });
7257
7258 })(jQuery);
7259 (function( $, undefined ) {
7260
7261 /*jshint loopfunc: true */
7262
7263 function isOverAxis( x, reference, size ) {
7264 return ( x > reference ) && ( x < ( reference + size ) );
7265 }
7266
7267 function isFloating(item) {
7268 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
7269 }
7270
7271 $.widget("ui.sortable", $.ui.mouse, {
7272 version: "1.10.3",
7273 widgetEventPrefix: "sort",
7274 ready: false,
7275 options: {
7276 appendTo: "parent",
7277 axis: false,
7278 connectWith: false,
7279 containment: false,
7280 cursor: "auto",
7281 cursorAt: false,
7282 dropOnEmpty: true,
7283 forcePlaceholderSize: false,
7284 forceHelperSize: false,
7285 grid: false,
7286 handle: false,
7287 helper: "original",
7288 items: "> *",
7289 opacity: false,
7290 placeholder: false,
7291 revert: false,
7292 scroll: true,
7293 scrollSensitivity: 20,
7294 scrollSpeed: 20,
7295 scope: "default",
7296 tolerance: "intersect",
7297 zIndex: 1000,
7298
7299 // callbacks
7300 activate: null,
7301 beforeStop: null,
7302 change: null,
7303 deactivate: null,
7304 out: null,
7305 over: null,
7306 receive: null,
7307 remove: null,
7308 sort: null,
7309 start: null,
7310 stop: null,
7311 update: null
7312 },
7313 _create: function() {
7314
7315 var o = this.options;
7316 this.containerCache = {};
7317 this.element.addClass("ui-sortable");
7318
7319 //Get the items
7320 this.refresh();
7321
7322 //Let's determine if the items are being displayed horizontally
7323 this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
7324
7325 //Let's determine the parent's offset
7326 this.offset = this.element.offset();
7327
7328 //Initialize mouse events for interaction
7329 this._mouseInit();
7330
7331 //We're ready to go
7332 this.ready = true;
7333
7334 },
7335
7336 _destroy: function() {
7337 this.element
7338 .removeClass("ui-sortable ui-sortable-disabled");
7339 this._mouseDestroy();
7340
7341 for ( var i = this.items.length - 1; i >= 0; i-- ) {
7342 this.items[i].item.removeData(this.widgetName + "-item");
7343 }
7344
7345 return this;
7346 },
7347
7348 _setOption: function(key, value){
7349 if ( key === "disabled" ) {
7350 this.options[ key ] = value;
7351
7352 this.widget().toggleClass( "ui-sortable-disabled", !!value );
7353 } else {
7354 // Don't call widget base _setOption for disable as it adds ui-state-disabled class
7355 $.Widget.prototype._setOption.apply(this, arguments);
7356 }
7357 },
7358
7359 _mouseCapture: function(event, overrideHandle) {
7360 var currentItem = null,
7361 validHandle = false,
7362 that = this;
7363
7364 if (this.reverting) {
7365 return false;
7366 }
7367
7368 if(this.options.disabled || this.options.type === "static") {
7369 return false;
7370 }
7371
7372 //We have to refresh the items data once first
7373 this._refreshItems(event);
7374
7375 //Find out if the clicked node (or one of its parents) is a actual item in this.items
7376 $(event.target).parents().each(function() {
7377 if($.data(this, that.widgetName + "-item") === that) {
7378 currentItem = $(this);
7379 return false;
7380 }
7381 });
7382 if($.data(event.target, that.widgetName + "-item") === that) {
7383 currentItem = $(event.target);
7384 }
7385
7386 if(!currentItem) {
7387 return false;
7388 }
7389 if(this.options.handle && !overrideHandle) {
7390 $(this.options.handle, currentItem).find("*").addBack().each(function() {
7391 if(this === event.target) {
7392 validHandle = true;
7393 }
7394 });
7395 if(!validHandle) {
7396 return false;
7397 }
7398 }
7399
7400 this.currentItem = currentItem;
7401 this._removeCurrentsFromItems();
7402 return true;
7403
7404 },
7405
7406 _mouseStart: function(event, overrideHandle, noActivation) {
7407
7408 var i, body,
7409 o = this.options;
7410
7411 this.currentContainer = this;
7412
7413 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
7414 this.refreshPositions();
7415
7416 //Create and append the visible helper
7417 this.helper = this._createHelper(event);
7418
7419 //Cache the helper size
7420 this._cacheHelperProportions();
7421
7422 /*
7423 * - Position generation -
7424 * This block generates everything position related - it's the core of draggables.
7425 */
7426
7427 //Cache the margins of the original element
7428 this._cacheMargins();
7429
7430 //Get the next scrolling parent
7431 this.scrollParent = this.helper.scrollParent();
7432
7433 //The element's absolute position on the page minus margins
7434 this.offset = this.currentItem.offset();
7435 this.offset = {
7436 top: this.offset.top - this.margins.top,
7437 left: this.offset.left - this.margins.left
7438 };
7439
7440 $.extend(this.offset, {
7441 click: { //Where the click happened, relative to the element
7442 left: event.pageX - this.offset.left,
7443 top: event.pageY - this.offset.top
7444 },
7445 parent: this._getParentOffset(),
7446 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
7447 });
7448
7449 // Only after we got the offset, we can change the helper's position to absolute
7450 // TODO: Still need to figure out a way to make relative sorting possible
7451 this.helper.css("position", "absolute");
7452 this.cssPosition = this.helper.css("position");
7453
7454 //Generate the original position
7455 this.originalPosition = this._generatePosition(event);
7456 this.originalPageX = event.pageX;
7457 this.originalPageY = event.pageY;
7458
7459 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
7460 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
7461
7462 //Cache the former DOM position
7463 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
7464
7465 //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
7466 if(this.helper[0] !== this.currentItem[0]) {
7467 this.currentItem.hide();
7468 }
7469
7470 //Create the placeholder
7471 this._createPlaceholder();
7472
7473 //Set a containment if given in the options
7474 if(o.containment) {
7475 this._setContainment();
7476 }
7477
7478 if( o.cursor && o.cursor !== "auto" ) { // cursor option
7479 body = this.document.find( "body" );
7480
7481 // support: IE
7482 this.storedCursor = body.css( "cursor" );
7483 body.css( "cursor", o.cursor );
7484
7485 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
7486 }
7487
7488 if(o.opacity) { // opacity option
7489 if (this.helper.css("opacity")) {
7490 this._storedOpacity = this.helper.css("opacity");
7491 }
7492 this.helper.css("opacity", o.opacity);
7493 }
7494
7495 if(o.zIndex) { // zIndex option
7496 if (this.helper.css("zIndex")) {
7497 this._storedZIndex = this.helper.css("zIndex");
7498 }
7499 this.helper.css("zIndex", o.zIndex);
7500 }
7501
7502 //Prepare scrolling
7503 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
7504 this.overflowOffset = this.scrollParent.offset();
7505 }
7506
7507 //Call callbacks
7508 this._trigger("start", event, this._uiHash());
7509
7510 //Recache the helper size
7511 if(!this._preserveHelperProportions) {
7512 this._cacheHelperProportions();
7513 }
7514
7515
7516 //Post "activate" events to possible containers
7517 if( !noActivation ) {
7518 for ( i = this.containers.length - 1; i >= 0; i-- ) {
7519 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
7520 }
7521 }
7522
7523 //Prepare possible droppables
7524 if($.ui.ddmanager) {
7525 $.ui.ddmanager.current = this;
7526 }
7527
7528 if ($.ui.ddmanager && !o.dropBehaviour) {
7529 $.ui.ddmanager.prepareOffsets(this, event);
7530 }
7531
7532 this.dragging = true;
7533
7534 this.helper.addClass("ui-sortable-helper");
7535 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
7536 return true;
7537
7538 },
7539
7540 _mouseDrag: function(event) {
7541 var i, item, itemElement, intersection,
7542 o = this.options,
7543 scrolled = false;
7544
7545 //Compute the helpers position
7546 this.position = this._generatePosition(event);
7547 this.positionAbs = this._convertPositionTo("absolute");
7548
7549 if (!this.lastPositionAbs) {
7550 this.lastPositionAbs = this.positionAbs;
7551 }
7552
7553 //Do scrolling
7554 if(this.options.scroll) {
7555 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
7556
7557 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
7558 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
7559 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
7560 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
7561 }
7562
7563 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
7564 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
7565 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
7566 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
7567 }
7568
7569 } else {
7570
7571 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
7572 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
7573 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
7574 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
7575 }
7576
7577 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
7578 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
7579 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
7580 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
7581 }
7582
7583 }
7584
7585 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
7586 $.ui.ddmanager.prepareOffsets(this, event);
7587 }
7588 }
7589
7590 //Regenerate the absolute position used for position checks
7591 this.positionAbs = this._convertPositionTo("absolute");
7592
7593 //Set the helper position
7594 if(!this.options.axis || this.options.axis !== "y") {
7595 this.helper[0].style.left = this.position.left+"px";
7596 }
7597 if(!this.options.axis || this.options.axis !== "x") {
7598 this.helper[0].style.top = this.position.top+"px";
7599 }
7600
7601 //Rearrange
7602 for (i = this.items.length - 1; i >= 0; i--) {
7603
7604 //Cache variables and intersection, continue if no intersection
7605 item = this.items[i];
7606 itemElement = item.item[0];
7607 intersection = this._intersectsWithPointer(item);
7608 if (!intersection) {
7609 continue;
7610 }
7611
7612 // Only put the placeholder inside the current Container, skip all
7613 // items form other containers. This works because when moving
7614 // an item from one container to another the
7615 // currentContainer is switched before the placeholder is moved.
7616 //
7617 // Without this moving items in "sub-sortables" can cause the placeholder to jitter
7618 // beetween the outer and inner container.
7619 if (item.instance !== this.currentContainer) {
7620 continue;
7621 }
7622
7623 // cannot intersect with itself
7624 // no useless actions that have been done before
7625 // no action if the item moved is the parent of the item checked
7626 if (itemElement !== this.currentItem[0] &&
7627 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
7628 !$.contains(this.placeholder[0], itemElement) &&
7629 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
7630 ) {
7631
7632 this.direction = intersection === 1 ? "down" : "up";
7633
7634 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
7635 this._rearrange(event, item);
7636 } else {
7637 break;
7638 }
7639
7640 this._trigger("change", event, this._uiHash());
7641 break;
7642 }
7643 }
7644
7645 //Post events to containers
7646 this._contactContainers(event);
7647
7648 //Interconnect with droppables
7649 if($.ui.ddmanager) {
7650 $.ui.ddmanager.drag(this, event);
7651 }
7652
7653 //Call callbacks
7654 this._trigger("sort", event, this._uiHash());
7655
7656 this.lastPositionAbs = this.positionAbs;
7657 return false;
7658
7659 },
7660
7661 _mouseStop: function(event, noPropagation) {
7662
7663 if(!event) {
7664 return;
7665 }
7666
7667 //If we are using droppables, inform the manager about the drop
7668 if ($.ui.ddmanager && !this.options.dropBehaviour) {
7669 $.ui.ddmanager.drop(this, event);
7670 }
7671
7672 if(this.options.revert) {
7673 var that = this,
7674 cur = this.placeholder.offset(),
7675 axis = this.options.axis,
7676 animation = {};
7677
7678 if ( !axis || axis === "x" ) {
7679 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
7680 }
7681 if ( !axis || axis === "y" ) {
7682 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
7683 }
7684 this.reverting = true;
7685 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
7686 that._clear(event);
7687 });
7688 } else {
7689 this._clear(event, noPropagation);
7690 }
7691
7692 return false;
7693
7694 },
7695
7696 cancel: function() {
7697
7698 if(this.dragging) {
7699
7700 this._mouseUp({ target: null });
7701
7702 if(this.options.helper === "original") {
7703 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
7704 } else {
7705 this.currentItem.show();
7706 }
7707
7708 //Post deactivating events to containers
7709 for (var i = this.containers.length - 1; i >= 0; i--){
7710 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
7711 if(this.containers[i].containerCache.over) {
7712 this.containers[i]._trigger("out", null, this._uiHash(this));
7713 this.containers[i].containerCache.over = 0;
7714 }
7715 }
7716
7717 }
7718
7719 if (this.placeholder) {
7720 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
7721 if(this.placeholder[0].parentNode) {
7722 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
7723 }
7724 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
7725 this.helper.remove();
7726 }
7727
7728 $.extend(this, {
7729 helper: null,
7730 dragging: false,
7731 reverting: false,
7732 _noFinalSort: null
7733 });
7734
7735 if(this.domPosition.prev) {
7736 $(this.domPosition.prev).after(this.currentItem);
7737 } else {
7738 $(this.domPosition.parent).prepend(this.currentItem);
7739 }
7740 }
7741
7742 return this;
7743
7744 },
7745
7746 serialize: function(o) {
7747
7748 var items = this._getItemsAsjQuery(o && o.connected),
7749 str = [];
7750 o = o || {};
7751
7752 $(items).each(function() {
7753 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
7754 if (res) {
7755 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
7756 }
7757 });
7758
7759 if(!str.length && o.key) {
7760 str.push(o.key + "=");
7761 }
7762
7763 return str.join("&");
7764
7765 },
7766
7767 toArray: function(o) {
7768
7769 var items = this._getItemsAsjQuery(o && o.connected),
7770 ret = [];
7771
7772 o = o || {};
7773
7774 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
7775 return ret;
7776
7777 },
7778
7779 /* Be careful with the following core functions */
7780 _intersectsWith: function(item) {
7781
7782 var x1 = this.positionAbs.left,
7783 x2 = x1 + this.helperProportions.width,
7784 y1 = this.positionAbs.top,
7785 y2 = y1 + this.helperProportions.height,
7786 l = item.left,
7787 r = l + item.width,
7788 t = item.top,
7789 b = t + item.height,
7790 dyClick = this.offset.click.top,
7791 dxClick = this.offset.click.left,
7792 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
7793 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
7794 isOverElement = isOverElementHeight && isOverElementWidth;
7795
7796 if ( this.options.tolerance === "pointer" ||
7797 this.options.forcePointerForContainers ||
7798 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
7799 ) {
7800 return isOverElement;
7801 } else {
7802
7803 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
7804 x2 - (this.helperProportions.width / 2) < r && // Left Half
7805 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
7806 y2 - (this.helperProportions.height / 2) < b ); // Top Half
7807
7808 }
7809 },
7810
7811 _intersectsWithPointer: function(item) {
7812
7813 var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
7814 isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
7815 isOverElement = isOverElementHeight && isOverElementWidth,
7816 verticalDirection = this._getDragVerticalDirection(),
7817 horizontalDirection = this._getDragHorizontalDirection();
7818
7819 if (!isOverElement) {
7820 return false;
7821 }
7822
7823 return this.floating ?
7824 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
7825 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
7826
7827 },
7828
7829 _intersectsWithSides: function(item) {
7830
7831 var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
7832 isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
7833 verticalDirection = this._getDragVerticalDirection(),
7834 horizontalDirection = this._getDragHorizontalDirection();
7835
7836 if (this.floating && horizontalDirection) {
7837 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
7838 } else {
7839 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
7840 }
7841
7842 },
7843
7844 _getDragVerticalDirection: function() {
7845 var delta = this.positionAbs.top - this.lastPositionAbs.top;
7846 return delta !== 0 && (delta > 0 ? "down" : "up");
7847 },
7848
7849 _getDragHorizontalDirection: function() {
7850 var delta = this.positionAbs.left - this.lastPositionAbs.left;
7851 return delta !== 0 && (delta > 0 ? "right" : "left");
7852 },
7853
7854 refresh: function(event) {
7855 this._refreshItems(event);
7856 this.refreshPositions();
7857 return this;
7858 },
7859
7860 _connectWith: function() {
7861 var options = this.options;
7862 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
7863 },
7864
7865 _getItemsAsjQuery: function(connected) {
7866
7867 var i, j, cur, inst,
7868 items = [],
7869 queries = [],
7870 connectWith = this._connectWith();
7871
7872 if(connectWith && connected) {
7873 for (i = connectWith.length - 1; i >= 0; i--){
7874 cur = $(connectWith[i]);
7875 for ( j = cur.length - 1; j >= 0; j--){
7876 inst = $.data(cur[j], this.widgetFullName);
7877 if(inst && inst !== this && !inst.options.disabled) {
7878 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
7879 }
7880 }
7881 }
7882 }
7883
7884 queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
7885
7886 for (i = queries.length - 1; i >= 0; i--){
7887 queries[i][0].each(function() {
7888 items.push(this);
7889 });
7890 }
7891
7892 return $(items);
7893
7894 },
7895
7896 _removeCurrentsFromItems: function() {
7897
7898 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
7899
7900 this.items = $.grep(this.items, function (item) {
7901 for (var j=0; j < list.length; j++) {
7902 if(list[j] === item.item[0]) {
7903 return false;
7904 }
7905 }
7906 return true;
7907 });
7908
7909 },
7910
7911 _refreshItems: function(event) {
7912
7913 this.items = [];
7914 this.containers = [this];
7915
7916 var i, j, cur, inst, targetData, _queries, item, queriesLength,
7917 items = this.items,
7918 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
7919 connectWith = this._connectWith();
7920
7921 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
7922 for (i = connectWith.length - 1; i >= 0; i--){
7923 cur = $(connectWith[i]);
7924 for (j = cur.length - 1; j >= 0; j--){
7925 inst = $.data(cur[j], this.widgetFullName);
7926 if(inst && inst !== this && !inst.options.disabled) {
7927 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
7928 this.containers.push(inst);
7929 }
7930 }
7931 }
7932 }
7933
7934 for (i = queries.length - 1; i >= 0; i--) {
7935 targetData = queries[i][1];
7936 _queries = queries[i][0];
7937
7938 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
7939 item = $(_queries[j]);
7940
7941 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
7942
7943 items.push({
7944 item: item,
7945 instance: targetData,
7946 width: 0, height: 0,
7947 left: 0, top: 0
7948 });
7949 }
7950 }
7951
7952 },
7953
7954 refreshPositions: function(fast) {
7955
7956 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
7957 if(this.offsetParent && this.helper) {
7958 this.offset.parent = this._getParentOffset();
7959 }
7960
7961 var i, item, t, p;
7962
7963 for (i = this.items.length - 1; i >= 0; i--){
7964 item = this.items[i];
7965
7966 //We ignore calculating positions of all connected containers when we're not over them
7967 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
7968 continue;
7969 }
7970
7971 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
7972
7973 if (!fast) {
7974 item.width = t.outerWidth();
7975 item.height = t.outerHeight();
7976 }
7977
7978 p = t.offset();
7979 item.left = p.left;
7980 item.top = p.top;
7981 }
7982
7983 if(this.options.custom && this.options.custom.refreshContainers) {
7984 this.options.custom.refreshContainers.call(this);
7985 } else {
7986 for (i = this.containers.length - 1; i >= 0; i--){
7987 p = this.containers[i].element.offset();
7988 this.containers[i].containerCache.left = p.left;
7989 this.containers[i].containerCache.top = p.top;
7990 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
7991 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
7992 }
7993 }
7994
7995 return this;
7996 },
7997
7998 _createPlaceholder: function(that) {
7999 that = that || this;
8000 var className,
8001 o = that.options;
8002
8003 if(!o.placeholder || o.placeholder.constructor === String) {
8004 className = o.placeholder;
8005 o.placeholder = {
8006 element: function() {
8007
8008 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
8009 element = $( "<" + nodeName + ">", that.document[0] )
8010 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
8011 .removeClass("ui-sortable-helper");
8012
8013 if ( nodeName === "tr" ) {
8014 that.currentItem.children().each(function() {
8015 $( "<td>&#160;</td>", that.document[0] )
8016 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
8017 .appendTo( element );
8018 });
8019 } else if ( nodeName === "img" ) {
8020 element.attr( "src", that.currentItem.attr( "src" ) );
8021 }
8022
8023 if ( !className ) {
8024 element.css( "visibility", "hidden" );
8025 }
8026
8027 return element;
8028 },
8029 update: function(container, p) {
8030
8031 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
8032 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
8033 if(className && !o.forcePlaceholderSize) {
8034 return;
8035 }
8036
8037 //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
8038 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
8039 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
8040 }
8041 };
8042 }
8043
8044 //Create the placeholder
8045 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
8046
8047 //Append it after the actual current item
8048 that.currentItem.after(that.placeholder);
8049
8050 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
8051 o.placeholder.update(that, that.placeholder);
8052
8053 },
8054
8055 _contactContainers: function(event) {
8056 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
8057 innermostContainer = null,
8058 innermostIndex = null;
8059
8060 // get innermost container that intersects with item
8061 for (i = this.containers.length - 1; i >= 0; i--) {
8062
8063 // never consider a container that's located within the item itself
8064 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
8065 continue;
8066 }
8067
8068 if(this._intersectsWith(this.containers[i].containerCache)) {
8069
8070 // if we've already found a container and it's more "inner" than this, then continue
8071 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
8072 continue;
8073 }
8074
8075 innermostContainer = this.containers[i];
8076 innermostIndex = i;
8077
8078 } else {
8079 // container doesn't intersect. trigger "out" event if necessary
8080 if(this.containers[i].containerCache.over) {
8081 this.containers[i]._trigger("out", event, this._uiHash(this));
8082 this.containers[i].containerCache.over = 0;
8083 }
8084 }
8085
8086 }
8087
8088 // if no intersecting containers found, return
8089 if(!innermostContainer) {
8090 return;
8091 }
8092
8093 // move the item into the container if it's not there already
8094 if(this.containers.length === 1) {
8095 if (!this.containers[innermostIndex].containerCache.over) {
8096 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
8097 this.containers[innermostIndex].containerCache.over = 1;
8098 }
8099 } else {
8100
8101 //When entering a new container, we will find the item with the least distance and append our item near it
8102 dist = 10000;
8103 itemWithLeastDistance = null;
8104 floating = innermostContainer.floating || isFloating(this.currentItem);
8105 posProperty = floating ? "left" : "top";
8106 sizeProperty = floating ? "width" : "height";
8107 base = this.positionAbs[posProperty] + this.offset.click[posProperty];
8108 for (j = this.items.length - 1; j >= 0; j--) {
8109 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
8110 continue;
8111 }
8112 if(this.items[j].item[0] === this.currentItem[0]) {
8113 continue;
8114 }
8115 if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
8116 continue;
8117 }
8118 cur = this.items[j].item.offset()[posProperty];
8119 nearBottom = false;
8120 if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
8121 nearBottom = true;
8122 cur += this.items[j][sizeProperty];
8123 }
8124
8125 if(Math.abs(cur - base) < dist) {
8126 dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
8127 this.direction = nearBottom ? "up": "down";
8128 }
8129 }
8130
8131 //Check if dropOnEmpty is enabled
8132 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
8133 return;
8134 }
8135
8136 if(this.currentContainer === this.containers[innermostIndex]) {
8137 return;
8138 }
8139
8140 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
8141 this._trigger("change", event, this._uiHash());
8142 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
8143 this.currentContainer = this.containers[innermostIndex];
8144
8145 //Update the placeholder
8146 this.options.placeholder.update(this.currentContainer, this.placeholder);
8147
8148 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
8149 this.containers[innermostIndex].containerCache.over = 1;
8150 }
8151
8152
8153 },
8154
8155 _createHelper: function(event) {
8156
8157 var o = this.options,
8158 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
8159
8160 //Add the helper to the DOM if that didn't happen already
8161 if(!helper.parents("body").length) {
8162 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
8163 }
8164
8165 if(helper[0] === this.currentItem[0]) {
8166 this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
8167 }
8168
8169 if(!helper[0].style.width || o.forceHelperSize) {
8170 helper.width(this.currentItem.width());
8171 }
8172 if(!helper[0].style.height || o.forceHelperSize) {
8173 helper.height(this.currentItem.height());
8174 }
8175
8176 return helper;
8177
8178 },
8179
8180 _adjustOffsetFromHelper: function(obj) {
8181 if (typeof obj === "string") {
8182 obj = obj.split(" ");
8183 }
8184 if ($.isArray(obj)) {
8185 obj = {left: +obj[0], top: +obj[1] || 0};
8186 }
8187 if ("left" in obj) {
8188 this.offset.click.left = obj.left + this.margins.left;
8189 }
8190 if ("right" in obj) {
8191 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
8192 }
8193 if ("top" in obj) {
8194 this.offset.click.top = obj.top + this.margins.top;
8195 }
8196 if ("bottom" in obj) {
8197 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
8198 }
8199 },
8200
8201 _getParentOffset: function() {
8202
8203
8204 //Get the offsetParent and cache its position
8205 this.offsetParent = this.helper.offsetParent();
8206 var po = this.offsetParent.offset();
8207
8208 // This is a special case where we need to modify a offset calculated on start, since the following happened:
8209 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
8210 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
8211 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
8212 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
8213 po.left += this.scrollParent.scrollLeft();
8214 po.top += this.scrollParent.scrollTop();
8215 }
8216
8217 // This needs to be actually done for all browsers, since pageX/pageY includes this information
8218 // with an ugly IE fix
8219 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
8220 po = { top: 0, left: 0 };
8221 }
8222
8223 return {
8224 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
8225 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
8226 };
8227
8228 },
8229
8230 _getRelativeOffset: function() {
8231
8232 if(this.cssPosition === "relative") {
8233 var p = this.currentItem.position();
8234 return {
8235 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
8236 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
8237 };
8238 } else {
8239 return { top: 0, left: 0 };
8240 }
8241
8242 },
8243
8244 _cacheMargins: function() {
8245 this.margins = {
8246 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
8247 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
8248 };
8249 },
8250
8251 _cacheHelperProportions: function() {
8252 this.helperProportions = {
8253 width: this.helper.outerWidth(),
8254 height: this.helper.outerHeight()
8255 };
8256 },
8257
8258 _setContainment: function() {
8259
8260 var ce, co, over,
8261 o = this.options;
8262 if(o.containment === "parent") {
8263 o.containment = this.helper[0].parentNode;
8264 }
8265 if(o.containment === "document" || o.containment === "window") {
8266 this.containment = [
8267 0 - this.offset.relative.left - this.offset.parent.left,
8268 0 - this.offset.relative.top - this.offset.parent.top,
8269 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
8270 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
8271 ];
8272 }
8273
8274 if(!(/^(document|window|parent)$/).test(o.containment)) {
8275 ce = $(o.containment)[0];
8276 co = $(o.containment).offset();
8277 over = ($(ce).css("overflow") !== "hidden");
8278
8279 this.containment = [
8280 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
8281 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
8282 co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
8283 co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
8284 ];
8285 }
8286
8287 },
8288
8289 _convertPositionTo: function(d, pos) {
8290
8291 if(!pos) {
8292 pos = this.position;
8293 }
8294 var mod = d === "absolute" ? 1 : -1,
8295 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
8296 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
8297
8298 return {
8299 top: (
8300 pos.top + // The absolute mouse position
8301 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
8302 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
8303 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
8304 ),
8305 left: (
8306 pos.left + // The absolute mouse position
8307 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
8308 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
8309 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
8310 )
8311 };
8312
8313 },
8314
8315 _generatePosition: function(event) {
8316
8317 var top, left,
8318 o = this.options,
8319 pageX = event.pageX,
8320 pageY = event.pageY,
8321 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
8322
8323 // This is another very weird special case that only happens for relative elements:
8324 // 1. If the css position is relative
8325 // 2. and the scroll parent is the document or similar to the offset parent
8326 // we have to refresh the relative offset during the scroll so there are no jumps
8327 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
8328 this.offset.relative = this._getRelativeOffset();
8329 }
8330
8331 /*
8332 * - Position constraining -
8333 * Constrain the position to a mix of grid, containment.
8334 */
8335
8336 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
8337
8338 if(this.containment) {
8339 if(event.pageX - this.offset.click.left < this.containment[0]) {
8340 pageX = this.containment[0] + this.offset.click.left;
8341 }
8342 if(event.pageY - this.offset.click.top < this.containment[1]) {
8343 pageY = this.containment[1] + this.offset.click.top;
8344 }
8345 if(event.pageX - this.offset.click.left > this.containment[2]) {
8346 pageX = this.containment[2] + this.offset.click.left;
8347 }
8348 if(event.pageY - this.offset.click.top > this.containment[3]) {
8349 pageY = this.containment[3] + this.offset.click.top;
8350 }
8351 }
8352
8353 if(o.grid) {
8354 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
8355 pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
8356
8357 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
8358 pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
8359 }
8360
8361 }
8362
8363 return {
8364 top: (
8365 pageY - // The absolute mouse position
8366 this.offset.click.top - // Click offset (relative to the element)
8367 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
8368 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
8369 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
8370 ),
8371 left: (
8372 pageX - // The absolute mouse position
8373 this.offset.click.left - // Click offset (relative to the element)
8374 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
8375 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
8376 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
8377 )
8378 };
8379
8380 },
8381
8382 _rearrange: function(event, i, a, hardRefresh) {
8383
8384 a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
8385
8386 //Various things done here to improve the performance:
8387 // 1. we create a setTimeout, that calls refreshPositions
8388 // 2. on the instance, we have a counter variable, that get's higher after every append
8389 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
8390 // 4. this lets only the last addition to the timeout stack through
8391 this.counter = this.counter ? ++this.counter : 1;
8392 var counter = this.counter;
8393
8394 this._delay(function() {
8395 if(counter === this.counter) {
8396 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
8397 }
8398 });
8399
8400 },
8401
8402 _clear: function(event, noPropagation) {
8403
8404 this.reverting = false;
8405 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
8406 // everything else normalized again
8407 var i,
8408 delayedTriggers = [];
8409
8410 // We first have to update the dom position of the actual currentItem
8411 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
8412 if(!this._noFinalSort && this.currentItem.parent().length) {
8413 this.placeholder.before(this.currentItem);
8414 }
8415 this._noFinalSort = null;
8416
8417 if(this.helper[0] === this.currentItem[0]) {
8418 for(i in this._storedCSS) {
8419 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
8420 this._storedCSS[i] = "";
8421 }
8422 }
8423 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
8424 } else {
8425 this.currentItem.show();
8426 }
8427
8428 if(this.fromOutside && !noPropagation) {
8429 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
8430 }
8431 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
8432 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
8433 }
8434
8435 // Check if the items Container has Changed and trigger appropriate
8436 // events.
8437 if (this !== this.currentContainer) {
8438 if(!noPropagation) {
8439 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
8440 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
8441 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
8442 }
8443 }
8444
8445
8446 //Post events to containers
8447 for (i = this.containers.length - 1; i >= 0; i--){
8448 if(!noPropagation) {
8449 delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
8450 }
8451 if(this.containers[i].containerCache.over) {
8452 delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
8453 this.containers[i].containerCache.over = 0;
8454 }
8455 }
8456
8457 //Do what was originally in plugins
8458 if ( this.storedCursor ) {
8459 this.document.find( "body" ).css( "cursor", this.storedCursor );
8460 this.storedStylesheet.remove();
8461 }
8462 if(this._storedOpacity) {
8463 this.helper.css("opacity", this._storedOpacity);
8464 }
8465 if(this._storedZIndex) {
8466 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
8467 }
8468
8469 this.dragging = false;
8470 if(this.cancelHelperRemoval) {
8471 if(!noPropagation) {
8472 this._trigger("beforeStop", event, this._uiHash());
8473 for (i=0; i < delayedTriggers.length; i++) {
8474 delayedTriggers[i].call(this, event);
8475 } //Trigger all delayed events
8476 this._trigger("stop", event, this._uiHash());
8477 }
8478
8479 this.fromOutside = false;
8480 return false;
8481 }
8482
8483 if(!noPropagation) {
8484 this._trigger("beforeStop", event, this._uiHash());
8485 }
8486
8487 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
8488 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
8489
8490 if(this.helper[0] !== this.currentItem[0]) {
8491 this.helper.remove();
8492 }
8493 this.helper = null;
8494
8495 if(!noPropagation) {
8496 for (i=0; i < delayedTriggers.length; i++) {
8497 delayedTriggers[i].call(this, event);
8498 } //Trigger all delayed events
8499 this._trigger("stop", event, this._uiHash());
8500 }
8501
8502 this.fromOutside = false;
8503 return true;
8504
8505 },
8506
8507 _trigger: function() {
8508 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
8509 this.cancel();
8510 }
8511 },
8512
8513 _uiHash: function(_inst) {
8514 var inst = _inst || this;
8515 return {
8516 helper: inst.helper,
8517 placeholder: inst.placeholder || $([]),
8518 position: inst.position,
8519 originalPosition: inst.originalPosition,
8520 offset: inst.positionAbs,
8521 item: inst.currentItem,
8522 sender: _inst ? _inst.element : null
8523 };
8524 }
8525
8526 });
8527
8528 })(jQuery);
8529 (function( $, undefined ) {
8530
8531 var uid = 0,
8532 hideProps = {},
8533 showProps = {};
8534
8535 hideProps.height = hideProps.paddingTop = hideProps.paddingBottom =
8536 hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide";
8537 showProps.height = showProps.paddingTop = showProps.paddingBottom =
8538 showProps.borderTopWidth = showProps.borderBottomWidth = "show";
8539
8540 $.widget( "ui.accordion", {
8541 version: "1.10.3",
8542 options: {
8543 active: 0,
8544 animate: {},
8545 collapsible: false,
8546 event: "click",
8547 header: "> li > :first-child,> :not(li):even",
8548 heightStyle: "auto",
8549 icons: {
8550 activeHeader: "ui-icon-triangle-1-s",
8551 header: "ui-icon-triangle-1-e"
8552 },
8553
8554 // callbacks
8555 activate: null,
8556 beforeActivate: null
8557 },
8558
8559 _create: function() {
8560 var options = this.options;
8561 this.prevShow = this.prevHide = $();
8562 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
8563 // ARIA
8564 .attr( "role", "tablist" );
8565
8566 // don't allow collapsible: false and active: false / null
8567 if ( !options.collapsible && (options.active === false || options.active == null) ) {
8568 options.active = 0;
8569 }
8570
8571 this._processPanels();
8572 // handle negative values
8573 if ( options.active < 0 ) {
8574 options.active += this.headers.length;
8575 }
8576 this._refresh();
8577 },
8578
8579 _getCreateEventData: function() {
8580 return {
8581 header: this.active,
8582 panel: !this.active.length ? $() : this.active.next(),
8583 content: !this.active.length ? $() : this.active.next()
8584 };
8585 },
8586
8587 _createIcons: function() {
8588 var icons = this.options.icons;
8589 if ( icons ) {
8590 $( "<span>" )
8591 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
8592 .prependTo( this.headers );
8593 this.active.children( ".ui-accordion-header-icon" )
8594 .removeClass( icons.header )
8595 .addClass( icons.activeHeader );
8596 this.headers.addClass( "ui-accordion-icons" );
8597 }
8598 },
8599
8600 _destroyIcons: function() {
8601 this.headers
8602 .removeClass( "ui-accordion-icons" )
8603 .children( ".ui-accordion-header-icon" )
8604 .remove();
8605 },
8606
8607 _destroy: function() {
8608 var contents;
8609
8610 // clean up main element
8611 this.element
8612 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
8613 .removeAttr( "role" );
8614
8615 // clean up headers
8616 this.headers
8617 .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
8618 .removeAttr( "role" )
8619 .removeAttr( "aria-selected" )
8620 .removeAttr( "aria-controls" )
8621 .removeAttr( "tabIndex" )
8622 .each(function() {
8623 if ( /^ui-accordion/.test( this.id ) ) {
8624 this.removeAttribute( "id" );
8625 }
8626 });
8627 this._destroyIcons();
8628
8629 // clean up content panels
8630 contents = this.headers.next()
8631 .css( "display", "" )
8632 .removeAttr( "role" )
8633 .removeAttr( "aria-expanded" )
8634 .removeAttr( "aria-hidden" )
8635 .removeAttr( "aria-labelledby" )
8636 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" )
8637 .each(function() {
8638 if ( /^ui-accordion/.test( this.id ) ) {
8639 this.removeAttribute( "id" );
8640 }
8641 });
8642 if ( this.options.heightStyle !== "content" ) {
8643 contents.css( "height", "" );
8644 }
8645 },
8646
8647 _setOption: function( key, value ) {
8648 if ( key === "active" ) {
8649 // _activate() will handle invalid values and update this.options
8650 this._activate( value );
8651 return;
8652 }
8653
8654 if ( key === "event" ) {
8655 if ( this.options.event ) {
8656 this._off( this.headers, this.options.event );
8657 }
8658 this._setupEvents( value );
8659 }
8660
8661 this._super( key, value );
8662
8663 // setting collapsible: false while collapsed; open first panel
8664 if ( key === "collapsible" && !value && this.options.active === false ) {
8665 this._activate( 0 );
8666 }
8667
8668 if ( key === "icons" ) {
8669 this._destroyIcons();
8670 if ( value ) {
8671 this._createIcons();
8672 }
8673 }
8674
8675 // #5332 - opacity doesn't cascade to positioned elements in IE
8676 // so we need to add the disabled class to the headers and panels
8677 if ( key === "disabled" ) {
8678 this.headers.add( this.headers.next() )
8679 .toggleClass( "ui-state-disabled", !!value );
8680 }
8681 },
8682
8683 _keydown: function( event ) {
8684 /*jshint maxcomplexity:15*/
8685 if ( event.altKey || event.ctrlKey ) {
8686 return;
8687 }
8688
8689 var keyCode = $.ui.keyCode,
8690 length = this.headers.length,
8691 currentIndex = this.headers.index( event.target ),
8692 toFocus = false;
8693
8694 switch ( event.keyCode ) {
8695 case keyCode.RIGHT:
8696 case keyCode.DOWN:
8697 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
8698 break;
8699 case keyCode.LEFT:
8700 case keyCode.UP:
8701 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
8702 break;
8703 case keyCode.SPACE:
8704 case keyCode.ENTER:
8705 this._eventHandler( event );
8706 break;
8707 case keyCode.HOME:
8708 toFocus = this.headers[ 0 ];
8709 break;
8710 case keyCode.END:
8711 toFocus = this.headers[ length - 1 ];
8712 break;
8713 }
8714
8715 if ( toFocus ) {
8716 $( event.target ).attr( "tabIndex", -1 );
8717 $( toFocus ).attr( "tabIndex", 0 );
8718 toFocus.focus();
8719 event.preventDefault();
8720 }
8721 },
8722
8723 _panelKeyDown : function( event ) {
8724 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
8725 $( event.currentTarget ).prev().focus();
8726 }
8727 },
8728
8729 refresh: function() {
8730 var options = this.options;
8731 this._processPanels();
8732
8733 // was collapsed or no panel
8734 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
8735 options.active = false;
8736 this.active = $();
8737 // active false only when collapsible is true
8738 } else if ( options.active === false ) {
8739 this._activate( 0 );
8740 // was active, but active panel is gone
8741 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
8742 // all remaining panel are disabled
8743 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
8744 options.active = false;
8745 this.active = $();
8746 // activate previous panel
8747 } else {
8748 this._activate( Math.max( 0, options.active - 1 ) );
8749 }
8750 // was active, active panel still exists
8751 } else {
8752 // make sure active index is correct
8753 options.active = this.headers.index( this.active );
8754 }
8755
8756 this._destroyIcons();
8757
8758 this._refresh();
8759 },
8760
8761 _processPanels: function() {
8762 this.headers = this.element.find( this.options.header )
8763 .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" );
8764
8765 this.headers.next()
8766 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
8767 .filter(":not(.ui-accordion-content-active)")
8768 .hide();
8769 },
8770
8771 _refresh: function() {
8772 var maxHeight,
8773 options = this.options,
8774 heightStyle = options.heightStyle,
8775 parent = this.element.parent(),
8776 accordionId = this.accordionId = "ui-accordion-" +
8777 (this.element.attr( "id" ) || ++uid);
8778
8779 this.active = this._findActive( options.active )
8780 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
8781 .removeClass( "ui-corner-all" );
8782 this.active.next()
8783 .addClass( "ui-accordion-content-active" )
8784 .show();
8785
8786 this.headers
8787 .attr( "role", "tab" )
8788 .each(function( i ) {
8789 var header = $( this ),
8790 headerId = header.attr( "id" ),
8791 panel = header.next(),
8792 panelId = panel.attr( "id" );
8793 if ( !headerId ) {
8794 headerId = accordionId + "-header-" + i;
8795 header.attr( "id", headerId );
8796 }
8797 if ( !panelId ) {
8798 panelId = accordionId + "-panel-" + i;
8799 panel.attr( "id", panelId );
8800 }
8801 header.attr( "aria-controls", panelId );
8802 panel.attr( "aria-labelledby", headerId );
8803 })
8804 .next()
8805 .attr( "role", "tabpanel" );
8806
8807 this.headers
8808 .not( this.active )
8809 .attr({
8810 "aria-selected": "false",
8811 tabIndex: -1
8812 })
8813 .next()
8814 .attr({
8815 "aria-expanded": "false",
8816 "aria-hidden": "true"
8817 })
8818 .hide();
8819
8820 // make sure at least one header is in the tab order
8821 if ( !this.active.length ) {
8822 this.headers.eq( 0 ).attr( "tabIndex", 0 );
8823 } else {
8824 this.active.attr({
8825 "aria-selected": "true",
8826 tabIndex: 0
8827 })
8828 .next()
8829 .attr({
8830 "aria-expanded": "true",
8831 "aria-hidden": "false"
8832 });
8833 }
8834
8835 this._createIcons();
8836
8837 this._setupEvents( options.event );
8838
8839 if ( heightStyle === "fill" ) {
8840 maxHeight = parent.height();
8841 this.element.siblings( ":visible" ).each(function() {
8842 var elem = $( this ),
8843 position = elem.css( "position" );
8844
8845 if ( position === "absolute" || position === "fixed" ) {
8846 return;
8847 }
8848 maxHeight -= elem.outerHeight( true );
8849 });
8850
8851 this.headers.each(function() {
8852 maxHeight -= $( this ).outerHeight( true );
8853 });
8854
8855 this.headers.next()
8856 .each(function() {
8857 $( this ).height( Math.max( 0, maxHeight -
8858 $( this ).innerHeight() + $( this ).height() ) );
8859 })
8860 .css( "overflow", "auto" );
8861 } else if ( heightStyle === "auto" ) {
8862 maxHeight = 0;
8863 this.headers.next()
8864 .each(function() {
8865 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
8866 })
8867 .height( maxHeight );
8868 }
8869 },
8870
8871 _activate: function( index ) {
8872 var active = this._findActive( index )[ 0 ];
8873
8874 // trying to activate the already active panel
8875 if ( active === this.active[ 0 ] ) {
8876 return;
8877 }
8878
8879 // trying to collapse, simulate a click on the currently active header
8880 active = active || this.active[ 0 ];
8881
8882 this._eventHandler({
8883 target: active,
8884 currentTarget: active,
8885 preventDefault: $.noop
8886 });
8887 },
8888
8889 _findActive: function( selector ) {
8890 return typeof selector === "number" ? this.headers.eq( selector ) : $();
8891 },
8892
8893 _setupEvents: function( event ) {
8894 var events = {
8895 keydown: "_keydown"
8896 };
8897 if ( event ) {
8898 $.each( event.split(" "), function( index, eventName ) {
8899 events[ eventName ] = "_eventHandler";
8900 });
8901 }
8902
8903 this._off( this.headers.add( this.headers.next() ) );
8904 this._on( this.headers, events );
8905 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
8906 this._hoverable( this.headers );
8907 this._focusable( this.headers );
8908 },
8909
8910 _eventHandler: function( event ) {
8911 var options = this.options,
8912 active = this.active,
8913 clicked = $( event.currentTarget ),
8914 clickedIsActive = clicked[ 0 ] === active[ 0 ],
8915 collapsing = clickedIsActive && options.collapsible,
8916 toShow = collapsing ? $() : clicked.next(),
8917 toHide = active.next(),
8918 eventData = {
8919 oldHeader: active,
8920 oldPanel: toHide,
8921 newHeader: collapsing ? $() : clicked,
8922 newPanel: toShow
8923 };
8924
8925 event.preventDefault();
8926
8927 if (
8928 // click on active header, but not collapsible
8929 ( clickedIsActive && !options.collapsible ) ||
8930 // allow canceling activation
8931 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
8932 return;
8933 }
8934
8935 options.active = collapsing ? false : this.headers.index( clicked );
8936
8937 // when the call to ._toggle() comes after the class changes
8938 // it causes a very odd bug in IE 8 (see #6720)
8939 this.active = clickedIsActive ? $() : clicked;
8940 this._toggle( eventData );
8941
8942 // switch classes
8943 // corner classes on the previously active header stay after the animation
8944 active.removeClass( "ui-accordion-header-active ui-state-active" );
8945 if ( options.icons ) {
8946 active.children( ".ui-accordion-header-icon" )
8947 .removeClass( options.icons.activeHeader )
8948 .addClass( options.icons.header );
8949 }
8950
8951 if ( !clickedIsActive ) {
8952 clicked
8953 .removeClass( "ui-corner-all" )
8954 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
8955 if ( options.icons ) {
8956 clicked.children( ".ui-accordion-header-icon" )
8957 .removeClass( options.icons.header )
8958 .addClass( options.icons.activeHeader );
8959 }
8960
8961 clicked
8962 .next()
8963 .addClass( "ui-accordion-content-active" );
8964 }
8965 },
8966
8967 _toggle: function( data ) {
8968 var toShow = data.newPanel,
8969 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
8970
8971 // handle activating a panel during the animation for another activation
8972 this.prevShow.add( this.prevHide ).stop( true, true );
8973 this.prevShow = toShow;
8974 this.prevHide = toHide;
8975
8976 if ( this.options.animate ) {
8977 this._animate( toShow, toHide, data );
8978 } else {
8979 toHide.hide();
8980 toShow.show();
8981 this._toggleComplete( data );
8982 }
8983
8984 toHide.attr({
8985 "aria-expanded": "false",
8986 "aria-hidden": "true"
8987 });
8988 toHide.prev().attr( "aria-selected", "false" );
8989 // if we're switching panels, remove the old header from the tab order
8990 // if we're opening from collapsed state, remove the previous header from the tab order
8991 // if we're collapsing, then keep the collapsing header in the tab order
8992 if ( toShow.length && toHide.length ) {
8993 toHide.prev().attr( "tabIndex", -1 );
8994 } else if ( toShow.length ) {
8995 this.headers.filter(function() {
8996 return $( this ).attr( "tabIndex" ) === 0;
8997 })
8998 .attr( "tabIndex", -1 );
8999 }
9000
9001 toShow
9002 .attr({
9003 "aria-expanded": "true",
9004 "aria-hidden": "false"
9005 })
9006 .prev()
9007 .attr({
9008 "aria-selected": "true",
9009 tabIndex: 0
9010 });
9011 },
9012
9013 _animate: function( toShow, toHide, data ) {
9014 var total, easing, duration,
9015 that = this,
9016 adjust = 0,
9017 down = toShow.length &&
9018 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
9019 animate = this.options.animate || {},
9020 options = down && animate.down || animate,
9021 complete = function() {
9022 that._toggleComplete( data );
9023 };
9024
9025 if ( typeof options === "number" ) {
9026 duration = options;
9027 }
9028 if ( typeof options === "string" ) {
9029 easing = options;
9030 }
9031 // fall back from options to animation in case of partial down settings
9032 easing = easing || options.easing || animate.easing;
9033 duration = duration || options.duration || animate.duration;
9034
9035 if ( !toHide.length ) {
9036 return toShow.animate( showProps, duration, easing, complete );
9037 }
9038 if ( !toShow.length ) {
9039 return toHide.animate( hideProps, duration, easing, complete );
9040 }
9041
9042 total = toShow.show().outerHeight();
9043 toHide.animate( hideProps, {
9044 duration: duration,
9045 easing: easing,
9046 step: function( now, fx ) {
9047 fx.now = Math.round( now );
9048 }
9049 });
9050 toShow
9051 .hide()
9052 .animate( showProps, {
9053 duration: duration,
9054 easing: easing,
9055 complete: complete,
9056 step: function( now, fx ) {
9057 fx.now = Math.round( now );
9058 if ( fx.prop !== "height" ) {
9059 adjust += fx.now;
9060 } else if ( that.options.heightStyle !== "content" ) {
9061 fx.now = Math.round( total - toHide.outerHeight() - adjust );
9062 adjust = 0;
9063 }
9064 }
9065 });
9066 },
9067
9068 _toggleComplete: function( data ) {
9069 var toHide = data.oldPanel;
9070
9071 toHide
9072 .removeClass( "ui-accordion-content-active" )
9073 .prev()
9074 .removeClass( "ui-corner-top" )
9075 .addClass( "ui-corner-all" );
9076
9077 // Work around for rendering bug in IE (#5421)
9078 if ( toHide.length ) {
9079 toHide.parent()[0].className = toHide.parent()[0].className;
9080 }
9081
9082 this._trigger( "activate", null, data );
9083 }
9084 });
9085
9086 })( jQuery );
9087 (function( $, undefined ) {
9088
9089 // used to prevent race conditions with remote data sources
9090 var requestIndex = 0;
9091
9092 $.widget( "ui.autocomplete", {
9093 version: "1.10.3",
9094 defaultElement: "<input>",
9095 options: {
9096 appendTo: null,
9097 autoFocus: false,
9098 delay: 300,
9099 minLength: 1,
9100 position: {
9101 my: "left top",
9102 at: "left bottom",
9103 collision: "none"
9104 },
9105 source: null,
9106
9107 // callbacks
9108 change: null,
9109 close: null,
9110 focus: null,
9111 open: null,
9112 response: null,
9113 search: null,
9114 select: null
9115 },
9116
9117 pending: 0,
9118
9119 _create: function() {
9120 // Some browsers only repeat keydown events, not keypress events,
9121 // so we use the suppressKeyPress flag to determine if we've already
9122 // handled the keydown event. #7269
9123 // Unfortunately the code for & in keypress is the same as the up arrow,
9124 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
9125 // events when we know the keydown event was used to modify the
9126 // search term. #7799
9127 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
9128 nodeName = this.element[0].nodeName.toLowerCase(),
9129 isTextarea = nodeName === "textarea",
9130 isInput = nodeName === "input";
9131
9132 this.isMultiLine =
9133 // Textareas are always multi-line
9134 isTextarea ? true :
9135 // Inputs are always single-line, even if inside a contentEditable element
9136 // IE also treats inputs as contentEditable
9137 isInput ? false :
9138 // All other element types are determined by whether or not they're contentEditable
9139 this.element.prop( "isContentEditable" );
9140
9141 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
9142 this.isNewMenu = true;
9143
9144 this.element
9145 .addClass( "ui-autocomplete-input" )
9146 .attr( "autocomplete", "off" );
9147
9148 this._on( this.element, {
9149 keydown: function( event ) {
9150 /*jshint maxcomplexity:15*/
9151 if ( this.element.prop( "readOnly" ) ) {
9152 suppressKeyPress = true;
9153 suppressInput = true;
9154 suppressKeyPressRepeat = true;
9155 return;
9156 }
9157
9158 suppressKeyPress = false;
9159 suppressInput = false;
9160 suppressKeyPressRepeat = false;
9161 var keyCode = $.ui.keyCode;
9162 switch( event.keyCode ) {
9163 case keyCode.PAGE_UP:
9164 suppressKeyPress = true;
9165 this._move( "previousPage", event );
9166 break;
9167 case keyCode.PAGE_DOWN:
9168 suppressKeyPress = true;
9169 this._move( "nextPage", event );
9170 break;
9171 case keyCode.UP:
9172 suppressKeyPress = true;
9173 this._keyEvent( "previous", event );
9174 break;
9175 case keyCode.DOWN:
9176 suppressKeyPress = true;
9177 this._keyEvent( "next", event );
9178 break;
9179 case keyCode.ENTER:
9180 case keyCode.NUMPAD_ENTER:
9181 // when menu is open and has focus
9182 if ( this.menu.active ) {
9183 // #6055 - Opera still allows the keypress to occur
9184 // which causes forms to submit
9185 suppressKeyPress = true;
9186 event.preventDefault();
9187 this.menu.select( event );
9188 }
9189 break;
9190 case keyCode.TAB:
9191 if ( this.menu.active ) {
9192 this.menu.select( event );
9193 }
9194 break;
9195 case keyCode.ESCAPE:
9196 if ( this.menu.element.is( ":visible" ) ) {
9197 this._value( this.term );
9198 this.close( event );
9199 // Different browsers have different default behavior for escape
9200 // Single press can mean undo or clear
9201 // Double press in IE means clear the whole form
9202 event.preventDefault();
9203 }
9204 break;
9205 default:
9206 suppressKeyPressRepeat = true;
9207 // search timeout should be triggered before the input value is changed
9208 this._searchTimeout( event );
9209 break;
9210 }
9211 },
9212 keypress: function( event ) {
9213 if ( suppressKeyPress ) {
9214 suppressKeyPress = false;
9215 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
9216 event.preventDefault();
9217 }
9218 return;
9219 }
9220 if ( suppressKeyPressRepeat ) {
9221 return;
9222 }
9223
9224 // replicate some key handlers to allow them to repeat in Firefox and Opera
9225 var keyCode = $.ui.keyCode;
9226 switch( event.keyCode ) {
9227 case keyCode.PAGE_UP:
9228 this._move( "previousPage", event );
9229 break;
9230 case keyCode.PAGE_DOWN:
9231 this._move( "nextPage", event );
9232 break;
9233 case keyCode.UP:
9234 this._keyEvent( "previous", event );
9235 break;
9236 case keyCode.DOWN:
9237 this._keyEvent( "next", event );
9238 break;
9239 }
9240 },
9241 input: function( event ) {
9242 if ( suppressInput ) {
9243 suppressInput = false;
9244 event.preventDefault();
9245 return;
9246 }
9247 this._searchTimeout( event );
9248 },
9249 focus: function() {
9250 this.selectedItem = null;
9251 this.previous = this._value();
9252 },
9253 blur: function( event ) {
9254 if ( this.cancelBlur ) {
9255 delete this.cancelBlur;
9256 return;
9257 }
9258
9259 clearTimeout( this.searching );
9260 this.close( event );
9261 this._change( event );
9262 }
9263 });
9264
9265 this._initSource();
9266 this.menu = $( "<ul>" )
9267 .addClass( "ui-autocomplete ui-front" )
9268 .appendTo( this._appendTo() )
9269 .menu({
9270 // disable ARIA support, the live region takes care of that
9271 role: null
9272 })
9273 .hide()
9274 .data( "ui-menu" );
9275
9276 this._on( this.menu.element, {
9277 mousedown: function( event ) {
9278 // prevent moving focus out of the text field
9279 event.preventDefault();
9280
9281 // IE doesn't prevent moving focus even with event.preventDefault()
9282 // so we set a flag to know when we should ignore the blur event
9283 this.cancelBlur = true;
9284 this._delay(function() {
9285 delete this.cancelBlur;
9286 });
9287
9288 // clicking on the scrollbar causes focus to shift to the body
9289 // but we can't detect a mouseup or a click immediately afterward
9290 // so we have to track the next mousedown and close the menu if
9291 // the user clicks somewhere outside of the autocomplete
9292 var menuElement = this.menu.element[ 0 ];
9293 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
9294 this._delay(function() {
9295 var that = this;
9296 this.document.one( "mousedown", function( event ) {
9297 if ( event.target !== that.element[ 0 ] &&
9298 event.target !== menuElement &&
9299 !$.contains( menuElement, event.target ) ) {
9300 that.close();
9301 }
9302 });
9303 });
9304 }
9305 },
9306 menufocus: function( event, ui ) {
9307 // support: Firefox
9308 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
9309 if ( this.isNewMenu ) {
9310 this.isNewMenu = false;
9311 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
9312 this.menu.blur();
9313
9314 this.document.one( "mousemove", function() {
9315 $( event.target ).trigger( event.originalEvent );
9316 });
9317
9318 return;
9319 }
9320 }
9321
9322 var item = ui.item.data( "ui-autocomplete-item" );
9323 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
9324 // use value to match what will end up in the input, if it was a key event
9325 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
9326 this._value( item.value );
9327 }
9328 } else {
9329 // Normally the input is populated with the item's value as the
9330 // menu is navigated, causing screen readers to notice a change and
9331 // announce the item. Since the focus event was canceled, this doesn't
9332 // happen, so we update the live region so that screen readers can
9333 // still notice the change and announce it.
9334 this.liveRegion.text( item.value );
9335 }
9336 },
9337 menuselect: function( event, ui ) {
9338 var item = ui.item.data( "ui-autocomplete-item" ),
9339 previous = this.previous;
9340
9341 // only trigger when focus was lost (click on menu)
9342 if ( this.element[0] !== this.document[0].activeElement ) {
9343 this.element.focus();
9344 this.previous = previous;
9345 // #6109 - IE triggers two focus events and the second
9346 // is asynchronous, so we need to reset the previous
9347 // term synchronously and asynchronously :-(
9348 this._delay(function() {
9349 this.previous = previous;
9350 this.selectedItem = item;
9351 });
9352 }
9353
9354 if ( false !== this._trigger( "select", event, { item: item } ) ) {
9355 this._value( item.value );
9356 }
9357 // reset the term after the select event
9358 // this allows custom select handling to work properly
9359 this.term = this._value();
9360
9361 this.close( event );
9362 this.selectedItem = item;
9363 }
9364 });
9365
9366 this.liveRegion = $( "<span>", {
9367 role: "status",
9368 "aria-live": "polite"
9369 })
9370 .addClass( "ui-helper-hidden-accessible" )
9371 .insertBefore( this.element );
9372
9373 // turning off autocomplete prevents the browser from remembering the
9374 // value when navigating through history, so we re-enable autocomplete
9375 // if the page is unloaded before the widget is destroyed. #7790
9376 this._on( this.window, {
9377 beforeunload: function() {
9378 this.element.removeAttr( "autocomplete" );
9379 }
9380 });
9381 },
9382
9383 _destroy: function() {
9384 clearTimeout( this.searching );
9385 this.element
9386 .removeClass( "ui-autocomplete-input" )
9387 .removeAttr( "autocomplete" );
9388 this.menu.element.remove();
9389 this.liveRegion.remove();
9390 },
9391
9392 _setOption: function( key, value ) {
9393 this._super( key, value );
9394 if ( key === "source" ) {
9395 this._initSource();
9396 }
9397 if ( key === "appendTo" ) {
9398 this.menu.element.appendTo( this._appendTo() );
9399 }
9400 if ( key === "disabled" && value && this.xhr ) {
9401 this.xhr.abort();
9402 }
9403 },
9404
9405 _appendTo: function() {
9406 var element = this.options.appendTo;
9407
9408 if ( element ) {
9409 element = element.jquery || element.nodeType ?
9410 $( element ) :
9411 this.document.find( element ).eq( 0 );
9412 }
9413
9414 if ( !element ) {
9415 element = this.element.closest( ".ui-front" );
9416 }
9417
9418 if ( !element.length ) {
9419 element = this.document[0].body;
9420 }
9421
9422 return element;
9423 },
9424
9425 _initSource: function() {
9426 var array, url,
9427 that = this;
9428 if ( $.isArray(this.options.source) ) {
9429 array = this.options.source;
9430 this.source = function( request, response ) {
9431 response( $.ui.autocomplete.filter( array, request.term ) );
9432 };
9433 } else if ( typeof this.options.source === "string" ) {
9434 url = this.options.source;
9435 this.source = function( request, response ) {
9436 if ( that.xhr ) {
9437 that.xhr.abort();
9438 }
9439 that.xhr = $.ajax({
9440 url: url,
9441 data: request,
9442 dataType: "json",
9443 success: function( data ) {
9444 response( data );
9445 },
9446 error: function() {
9447 response( [] );
9448 }
9449 });
9450 };
9451 } else {
9452 this.source = this.options.source;
9453 }
9454 },
9455
9456 _searchTimeout: function( event ) {
9457 clearTimeout( this.searching );
9458 this.searching = this._delay(function() {
9459 // only search if the value has changed
9460 if ( this.term !== this._value() ) {
9461 this.selectedItem = null;
9462 this.search( null, event );
9463 }
9464 }, this.options.delay );
9465 },
9466
9467 search: function( value, event ) {
9468 value = value != null ? value : this._value();
9469
9470 // always save the actual value, not the one passed as an argument
9471 this.term = this._value();
9472
9473 if ( value.length < this.options.minLength ) {
9474 return this.close( event );
9475 }
9476
9477 if ( this._trigger( "search", event ) === false ) {
9478 return;
9479 }
9480
9481 return this._search( value );
9482 },
9483
9484 _search: function( value ) {
9485 this.pending++;
9486 this.element.addClass( "ui-autocomplete-loading" );
9487 this.cancelSearch = false;
9488
9489 this.source( { term: value }, this._response() );
9490 },
9491
9492 _response: function() {
9493 var that = this,
9494 index = ++requestIndex;
9495
9496 return function( content ) {
9497 if ( index === requestIndex ) {
9498 that.__response( content );
9499 }
9500
9501 that.pending--;
9502 if ( !that.pending ) {
9503 that.element.removeClass( "ui-autocomplete-loading" );
9504 }
9505 };
9506 },
9507
9508 __response: function( content ) {
9509 if ( content ) {
9510 content = this._normalize( content );
9511 }
9512 this._trigger( "response", null, { content: content } );
9513 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
9514 this._suggest( content );
9515 this._trigger( "open" );
9516 } else {
9517 // use ._close() instead of .close() so we don't cancel future searches
9518 this._close();
9519 }
9520 },
9521
9522 close: function( event ) {
9523 this.cancelSearch = true;
9524 this._close( event );
9525 },
9526
9527 _close: function( event ) {
9528 if ( this.menu.element.is( ":visible" ) ) {
9529 this.menu.element.hide();
9530 this.menu.blur();
9531 this.isNewMenu = true;
9532 this._trigger( "close", event );
9533 }
9534 },
9535
9536 _change: function( event ) {
9537 if ( this.previous !== this._value() ) {
9538 this._trigger( "change", event, { item: this.selectedItem } );
9539 }
9540 },
9541
9542 _normalize: function( items ) {
9543 // assume all items have the right format when the first item is complete
9544 if ( items.length && items[0].label && items[0].value ) {
9545 return items;
9546 }
9547 return $.map( items, function( item ) {
9548 if ( typeof item === "string" ) {
9549 return {
9550 label: item,
9551 value: item
9552 };
9553 }
9554 return $.extend({
9555 label: item.label || item.value,
9556 value: item.value || item.label
9557 }, item );
9558 });
9559 },
9560
9561 _suggest: function( items ) {
9562 var ul = this.menu.element.empty();
9563 this._renderMenu( ul, items );
9564 this.isNewMenu = true;
9565 this.menu.refresh();
9566
9567 // size and position menu
9568 ul.show();
9569 this._resizeMenu();
9570 ul.position( $.extend({
9571 of: this.element
9572 }, this.options.position ));
9573
9574 if ( this.options.autoFocus ) {
9575 this.menu.next();
9576 }
9577 },
9578
9579 _resizeMenu: function() {
9580 var ul = this.menu.element;
9581 ul.outerWidth( Math.max(
9582 // Firefox wraps long text (possibly a rounding bug)
9583 // so we add 1px to avoid the wrapping (#7513)
9584 ul.width( "" ).outerWidth() + 1,
9585 this.element.outerWidth()
9586 ) );
9587 },
9588
9589 _renderMenu: function( ul, items ) {
9590 var that = this;
9591 $.each( items, function( index, item ) {
9592 that._renderItemData( ul, item );
9593 });
9594 },
9595
9596 _renderItemData: function( ul, item ) {
9597 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
9598 },
9599
9600 _renderItem: function( ul, item ) {
9601 return $( "<li>" )
9602 .append( $( "<a>" ).text( item.label ) )
9603 .appendTo( ul );
9604 },
9605
9606 _move: function( direction, event ) {
9607 if ( !this.menu.element.is( ":visible" ) ) {
9608 this.search( null, event );
9609 return;
9610 }
9611 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
9612 this.menu.isLastItem() && /^next/.test( direction ) ) {
9613 this._value( this.term );
9614 this.menu.blur();
9615 return;
9616 }
9617 this.menu[ direction ]( event );
9618 },
9619
9620 widget: function() {
9621 return this.menu.element;
9622 },
9623
9624 _value: function() {
9625 return this.valueMethod.apply( this.element, arguments );
9626 },
9627
9628 _keyEvent: function( keyEvent, event ) {
9629 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
9630 this._move( keyEvent, event );
9631
9632 // prevents moving cursor to beginning/end of the text field in some browsers
9633 event.preventDefault();
9634 }
9635 }
9636 });
9637
9638 $.extend( $.ui.autocomplete, {
9639 escapeRegex: function( value ) {
9640 return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
9641 },
9642 filter: function(array, term) {
9643 var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
9644 return $.grep( array, function(value) {
9645 return matcher.test( value.label || value.value || value );
9646 });
9647 }
9648 });
9649
9650
9651 // live region extension, adding a `messages` option
9652 // NOTE: This is an experimental API. We are still investigating
9653 // a full solution for string manipulation and internationalization.
9654 $.widget( "ui.autocomplete", $.ui.autocomplete, {
9655 options: {
9656 messages: {
9657 noResults: "No search results.",
9658 results: function( amount ) {
9659 return amount + ( amount > 1 ? " results are" : " result is" ) +
9660 " available, use up and down arrow keys to navigate.";
9661 }
9662 }
9663 },
9664
9665 __response: function( content ) {
9666 var message;
9667 this._superApply( arguments );
9668 if ( this.options.disabled || this.cancelSearch ) {
9669 return;
9670 }
9671 if ( content && content.length ) {
9672 message = this.options.messages.results( content.length );
9673 } else {
9674 message = this.options.messages.noResults;
9675 }
9676 this.liveRegion.text( message );
9677 }
9678 });
9679
9680 }( jQuery ));
9681 (function( $, undefined ) {
9682
9683 var lastActive, startXPos, startYPos, clickDragged,
9684 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
9685 stateClasses = "ui-state-hover ui-state-active ",
9686 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
9687 formResetHandler = function() {
9688 var form = $( this );
9689 setTimeout(function() {
9690 form.find( ":ui-button" ).button( "refresh" );
9691 }, 1 );
9692 },
9693 radioGroup = function( radio ) {
9694 var name = radio.name,
9695 form = radio.form,
9696 radios = $( [] );
9697 if ( name ) {
9698 name = name.replace( /'/g, "\\'" );
9699 if ( form ) {
9700 radios = $( form ).find( "[name='" + name + "']" );
9701 } else {
9702 radios = $( "[name='" + name + "']", radio.ownerDocument )
9703 .filter(function() {
9704 return !this.form;
9705 });
9706 }
9707 }
9708 return radios;
9709 };
9710
9711 $.widget( "ui.button", {
9712 version: "1.10.3",
9713 defaultElement: "<button>",
9714 options: {
9715 disabled: null,
9716 text: true,
9717 label: null,
9718 icons: {
9719 primary: null,
9720 secondary: null
9721 }
9722 },
9723 _create: function() {
9724 this.element.closest( "form" )
9725 .unbind( "reset" + this.eventNamespace )
9726 .bind( "reset" + this.eventNamespace, formResetHandler );
9727
9728 if ( typeof this.options.disabled !== "boolean" ) {
9729 this.options.disabled = !!this.element.prop( "disabled" );
9730 } else {
9731 this.element.prop( "disabled", this.options.disabled );
9732 }
9733
9734 this._determineButtonType();
9735 this.hasTitle = !!this.buttonElement.attr( "title" );
9736
9737 var that = this,
9738 options = this.options,
9739 toggleButton = this.type === "checkbox" || this.type === "radio",
9740 activeClass = !toggleButton ? "ui-state-active" : "",
9741 focusClass = "ui-state-focus";
9742
9743 if ( options.label === null ) {
9744 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
9745 }
9746
9747 this._hoverable( this.buttonElement );
9748
9749 this.buttonElement
9750 .addClass( baseClasses )
9751 .attr( "role", "button" )
9752 .bind( "mouseenter" + this.eventNamespace, function() {
9753 if ( options.disabled ) {
9754 return;
9755 }
9756 if ( this === lastActive ) {
9757 $( this ).addClass( "ui-state-active" );
9758 }
9759 })
9760 .bind( "mouseleave" + this.eventNamespace, function() {
9761 if ( options.disabled ) {
9762 return;
9763 }
9764 $( this ).removeClass( activeClass );
9765 })
9766 .bind( "click" + this.eventNamespace, function( event ) {
9767 if ( options.disabled ) {
9768 event.preventDefault();
9769 event.stopImmediatePropagation();
9770 }
9771 });
9772
9773 this.element
9774 .bind( "focus" + this.eventNamespace, function() {
9775 // no need to check disabled, focus won't be triggered anyway
9776 that.buttonElement.addClass( focusClass );
9777 })
9778 .bind( "blur" + this.eventNamespace, function() {
9779 that.buttonElement.removeClass( focusClass );
9780 });
9781
9782 if ( toggleButton ) {
9783 this.element.bind( "change" + this.eventNamespace, function() {
9784 if ( clickDragged ) {
9785 return;
9786 }
9787 that.refresh();
9788 });
9789 // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
9790 // prevents issue where button state changes but checkbox/radio checked state
9791 // does not in Firefox (see ticket #6970)
9792 this.buttonElement
9793 .bind( "mousedown" + this.eventNamespace, function( event ) {
9794 if ( options.disabled ) {
9795 return;
9796 }
9797 clickDragged = false;
9798 startXPos = event.pageX;
9799 startYPos = event.pageY;
9800 })
9801 .bind( "mouseup" + this.eventNamespace, function( event ) {
9802 if ( options.disabled ) {
9803 return;
9804 }
9805 if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
9806 clickDragged = true;
9807 }
9808 });
9809 }
9810
9811 if ( this.type === "checkbox" ) {
9812 this.buttonElement.bind( "click" + this.eventNamespace, function() {
9813 if ( options.disabled || clickDragged ) {
9814 return false;
9815 }
9816 });
9817 } else if ( this.type === "radio" ) {
9818 this.buttonElement.bind( "click" + this.eventNamespace, function() {
9819 if ( options.disabled || clickDragged ) {
9820 return false;
9821 }
9822 $( this ).addClass( "ui-state-active" );
9823 that.buttonElement.attr( "aria-pressed", "true" );
9824
9825 var radio = that.element[ 0 ];
9826 radioGroup( radio )
9827 .not( radio )
9828 .map(function() {
9829 return $( this ).button( "widget" )[ 0 ];
9830 })
9831 .removeClass( "ui-state-active" )
9832 .attr( "aria-pressed", "false" );
9833 });
9834 } else {
9835 this.buttonElement
9836 .bind( "mousedown" + this.eventNamespace, function() {
9837 if ( options.disabled ) {
9838 return false;
9839 }
9840 $( this ).addClass( "ui-state-active" );
9841 lastActive = this;
9842 that.document.one( "mouseup", function() {
9843 lastActive = null;
9844 });
9845 })
9846 .bind( "mouseup" + this.eventNamespace, function() {
9847 if ( options.disabled ) {
9848 return false;
9849 }
9850 $( this ).removeClass( "ui-state-active" );
9851 })
9852 .bind( "keydown" + this.eventNamespace, function(event) {
9853 if ( options.disabled ) {
9854 return false;
9855 }
9856 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
9857 $( this ).addClass( "ui-state-active" );
9858 }
9859 })
9860 // see #8559, we bind to blur here in case the button element loses
9861 // focus between keydown and keyup, it would be left in an "active" state
9862 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
9863 $( this ).removeClass( "ui-state-active" );
9864 });
9865
9866 if ( this.buttonElement.is("a") ) {
9867 this.buttonElement.keyup(function(event) {
9868 if ( event.keyCode === $.ui.keyCode.SPACE ) {
9869 // TODO pass through original event correctly (just as 2nd argument doesn't work)
9870 $( this ).click();
9871 }
9872 });
9873 }
9874 }
9875
9876 // TODO: pull out $.Widget's handling for the disabled option into
9877 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
9878 // be overridden by individual plugins
9879 this._setOption( "disabled", options.disabled );
9880 this._resetButton();
9881 },
9882
9883 _determineButtonType: function() {
9884 var ancestor, labelSelector, checked;
9885
9886 if ( this.element.is("[type=checkbox]") ) {
9887 this.type = "checkbox";
9888 } else if ( this.element.is("[type=radio]") ) {
9889 this.type = "radio";
9890 } else if ( this.element.is("input") ) {
9891 this.type = "input";
9892 } else {
9893 this.type = "button";
9894 }
9895
9896 if ( this.type === "checkbox" || this.type === "radio" ) {
9897 // we don't search against the document in case the element
9898 // is disconnected from the DOM
9899 ancestor = this.element.parents().last();
9900 labelSelector = "label[for='" + this.element.attr("id") + "']";
9901 this.buttonElement = ancestor.find( labelSelector );
9902 if ( !this.buttonElement.length ) {
9903 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
9904 this.buttonElement = ancestor.filter( labelSelector );
9905 if ( !this.buttonElement.length ) {
9906 this.buttonElement = ancestor.find( labelSelector );
9907 }
9908 }
9909 this.element.addClass( "ui-helper-hidden-accessible" );
9910
9911 checked = this.element.is( ":checked" );
9912 if ( checked ) {
9913 this.buttonElement.addClass( "ui-state-active" );
9914 }
9915 this.buttonElement.prop( "aria-pressed", checked );
9916 } else {
9917 this.buttonElement = this.element;
9918 }
9919 },
9920
9921 widget: function() {
9922 return this.buttonElement;
9923 },
9924
9925 _destroy: function() {
9926 this.element
9927 .removeClass( "ui-helper-hidden-accessible" );
9928 this.buttonElement
9929 .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
9930 .removeAttr( "role" )
9931 .removeAttr( "aria-pressed" )
9932 .html( this.buttonElement.find(".ui-button-text").html() );
9933
9934 if ( !this.hasTitle ) {
9935 this.buttonElement.removeAttr( "title" );
9936 }
9937 },
9938
9939 _setOption: function( key, value ) {
9940 this._super( key, value );
9941 if ( key === "disabled" ) {
9942 if ( value ) {
9943 this.element.prop( "disabled", true );
9944 } else {
9945 this.element.prop( "disabled", false );
9946 }
9947 return;
9948 }
9949 this._resetButton();
9950 },
9951
9952 refresh: function() {
9953 //See #8237 & #8828
9954 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
9955
9956 if ( isDisabled !== this.options.disabled ) {
9957 this._setOption( "disabled", isDisabled );
9958 }
9959 if ( this.type === "radio" ) {
9960 radioGroup( this.element[0] ).each(function() {
9961 if ( $( this ).is( ":checked" ) ) {
9962 $( this ).button( "widget" )
9963 .addClass( "ui-state-active" )
9964 .attr( "aria-pressed", "true" );
9965 } else {
9966 $( this ).button( "widget" )
9967 .removeClass( "ui-state-active" )
9968 .attr( "aria-pressed", "false" );
9969 }
9970 });
9971 } else if ( this.type === "checkbox" ) {
9972 if ( this.element.is( ":checked" ) ) {
9973 this.buttonElement
9974 .addClass( "ui-state-active" )
9975 .attr( "aria-pressed", "true" );
9976 } else {
9977 this.buttonElement
9978 .removeClass( "ui-state-active" )
9979 .attr( "aria-pressed", "false" );
9980 }
9981 }
9982 },
9983
9984 _resetButton: function() {
9985 if ( this.type === "input" ) {
9986 if ( this.options.label ) {
9987 this.element.val( this.options.label );
9988 }
9989 return;
9990 }
9991 var buttonElement = this.buttonElement.removeClass( typeClasses ),
9992 buttonText = $( "<span></span>", this.document[0] )
9993 .addClass( "ui-button-text" )
9994 .html( this.options.label )
9995 .appendTo( buttonElement.empty() )
9996 .text(),
9997 icons = this.options.icons,
9998 multipleIcons = icons.primary && icons.secondary,
9999 buttonClasses = [];
10000
10001 if ( icons.primary || icons.secondary ) {
10002 if ( this.options.text ) {
10003 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
10004 }
10005
10006 if ( icons.primary ) {
10007 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
10008 }
10009
10010 if ( icons.secondary ) {
10011 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
10012 }
10013
10014 if ( !this.options.text ) {
10015 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
10016
10017 if ( !this.hasTitle ) {
10018 buttonElement.attr( "title", $.trim( buttonText ) );
10019 }
10020 }
10021 } else {
10022 buttonClasses.push( "ui-button-text-only" );
10023 }
10024 buttonElement.addClass( buttonClasses.join( " " ) );
10025 }
10026 });
10027
10028 $.widget( "ui.buttonset", {
10029 version: "1.10.3",
10030 options: {
10031 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
10032 },
10033
10034 _create: function() {
10035 this.element.addClass( "ui-buttonset" );
10036 },
10037
10038 _init: function() {
10039 this.refresh();
10040 },
10041
10042 _setOption: function( key, value ) {
10043 if ( key === "disabled" ) {
10044 this.buttons.button( "option", key, value );
10045 }
10046
10047 this._super( key, value );
10048 },
10049
10050 refresh: function() {
10051 var rtl = this.element.css( "direction" ) === "rtl";
10052
10053 this.buttons = this.element.find( this.options.items )
10054 .filter( ":ui-button" )
10055 .button( "refresh" )
10056 .end()
10057 .not( ":ui-button" )
10058 .button()
10059 .end()
10060 .map(function() {
10061 return $( this ).button( "widget" )[ 0 ];
10062 })
10063 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
10064 .filter( ":first" )
10065 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
10066 .end()
10067 .filter( ":last" )
10068 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
10069 .end()
10070 .end();
10071 },
10072
10073 _destroy: function() {
10074 this.element.removeClass( "ui-buttonset" );
10075 this.buttons
10076 .map(function() {
10077 return $( this ).button( "widget" )[ 0 ];
10078 })
10079 .removeClass( "ui-corner-left ui-corner-right" )
10080 .end()
10081 .button( "destroy" );
10082 }
10083 });
10084
10085 }( jQuery ) );
10086 (function( $, undefined ) {
10087
10088 $.extend($.ui, { datepicker: { version: "1.10.3" } });
10089
10090 var PROP_NAME = "datepicker",
10091 instActive;
10092
10093 /* Date picker manager.
10094 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
10095 Settings for (groups of) date pickers are maintained in an instance object,
10096 allowing multiple different settings on the same page. */
10097
10098 function Datepicker() {
10099 this._curInst = null; // The current instance in use
10100 this._keyEvent = false; // If the last event was a key event
10101 this._disabledInputs = []; // List of date picker inputs that have been disabled
10102 this._datepickerShowing = false; // True if the popup picker is showing , false if not
10103 this._inDialog = false; // True if showing within a "dialog", false if not
10104 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
10105 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
10106 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
10107 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
10108 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
10109 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
10110 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
10111 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
10112 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
10113 this.regional = []; // Available regional settings, indexed by language code
10114 this.regional[""] = { // Default regional settings
10115 closeText: "Done", // Display text for close link
10116 prevText: "Prev", // Display text for previous month link
10117 nextText: "Next", // Display text for next month link
10118 currentText: "Today", // Display text for current month link
10119 monthNames: ["January","February","March","April","May","June",
10120 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
10121 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
10122 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
10123 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
10124 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
10125 weekHeader: "Wk", // Column header for week of the year
10126 dateFormat: "mm/dd/yy", // See format options on parseDate
10127 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
10128 isRTL: false, // True if right-to-left language, false if left-to-right
10129 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
10130 yearSuffix: "" // Additional text to append to the year in the month headers
10131 };
10132 this._defaults = { // Global defaults for all the date picker instances
10133 showOn: "focus", // "focus" for popup on focus,
10134 // "button" for trigger button, or "both" for either
10135 showAnim: "fadeIn", // Name of jQuery animation for popup
10136 showOptions: {}, // Options for enhanced animations
10137 defaultDate: null, // Used when field is blank: actual date,
10138 // +/-number for offset from today, null for today
10139 appendText: "", // Display text following the input box, e.g. showing the format
10140 buttonText: "...", // Text for trigger button
10141 buttonImage: "", // URL for trigger button image
10142 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
10143 hideIfNoPrevNext: false, // True to hide next/previous month links
10144 // if not applicable, false to just disable them
10145 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
10146 gotoCurrent: false, // True if today link goes back to current selection instead
10147 changeMonth: false, // True if month can be selected directly, false if only prev/next
10148 changeYear: false, // True if year can be selected directly, false if only prev/next
10149 yearRange: "c-10:c+10", // Range of years to display in drop-down,
10150 // either relative to today's year (-nn:+nn), relative to currently displayed year
10151 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
10152 showOtherMonths: false, // True to show dates in other months, false to leave blank
10153 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
10154 showWeek: false, // True to show week of the year, false to not show it
10155 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
10156 // takes a Date and returns the number of the week for it
10157 shortYearCutoff: "+10", // Short year values < this are in the current century,
10158 // > this are in the previous century,
10159 // string value starting with "+" for current year + value
10160 minDate: null, // The earliest selectable date, or null for no limit
10161 maxDate: null, // The latest selectable date, or null for no limit
10162 duration: "fast", // Duration of display/closure
10163 beforeShowDay: null, // Function that takes a date and returns an array with
10164 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
10165 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
10166 beforeShow: null, // Function that takes an input field and
10167 // returns a set of custom settings for the date picker
10168 onSelect: null, // Define a callback function when a date is selected
10169 onChangeMonthYear: null, // Define a callback function when the month or year is changed
10170 onClose: null, // Define a callback function when the datepicker is closed
10171 numberOfMonths: 1, // Number of months to show at a time
10172 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
10173 stepMonths: 1, // Number of months to step back/forward
10174 stepBigMonths: 12, // Number of months to step back/forward for the big links
10175 altField: "", // Selector for an alternate field to store selected dates into
10176 altFormat: "", // The date format to use for the alternate field
10177 constrainInput: true, // The input is constrained by the current date format
10178 showButtonPanel: false, // True to show button panel, false to not show it
10179 autoSize: false, // True to size the input for the date format, false to leave as is
10180 disabled: false // The initial disabled state
10181 };
10182 $.extend(this._defaults, this.regional[""]);
10183 this.dpDiv = bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
10184 }
10185
10186 $.extend(Datepicker.prototype, {
10187 /* Class name added to elements to indicate already configured with a date picker. */
10188 markerClassName: "hasDatepicker",
10189
10190 //Keep track of the maximum number of rows displayed (see #7043)
10191 maxRows: 4,
10192
10193 // TODO rename to "widget" when switching to widget factory
10194 _widgetDatepicker: function() {
10195 return this.dpDiv;
10196 },
10197
10198 /* Override the default settings for all instances of the date picker.
10199 * @param settings object - the new settings to use as defaults (anonymous object)
10200 * @return the manager object
10201 */
10202 setDefaults: function(settings) {
10203 extendRemove(this._defaults, settings || {});
10204 return this;
10205 },
10206
10207 /* Attach the date picker to a jQuery selection.
10208 * @param target element - the target input field or division or span
10209 * @param settings object - the new settings to use for this date picker instance (anonymous)
10210 */
10211 _attachDatepicker: function(target, settings) {
10212 var nodeName, inline, inst;
10213 nodeName = target.nodeName.toLowerCase();
10214 inline = (nodeName === "div" || nodeName === "span");
10215 if (!target.id) {
10216 this.uuid += 1;
10217 target.id = "dp" + this.uuid;
10218 }
10219 inst = this._newInst($(target), inline);
10220 inst.settings = $.extend({}, settings || {});
10221 if (nodeName === "input") {
10222 this._connectDatepicker(target, inst);
10223 } else if (inline) {
10224 this._inlineDatepicker(target, inst);
10225 }
10226 },
10227
10228 /* Create a new instance object. */
10229 _newInst: function(target, inline) {
10230 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
10231 return {id: id, input: target, // associated target
10232 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
10233 drawMonth: 0, drawYear: 0, // month being drawn
10234 inline: inline, // is datepicker inline or not
10235 dpDiv: (!inline ? this.dpDiv : // presentation div
10236 bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
10237 },
10238
10239 /* Attach the date picker to an input field. */
10240 _connectDatepicker: function(target, inst) {
10241 var input = $(target);
10242 inst.append = $([]);
10243 inst.trigger = $([]);
10244 if (input.hasClass(this.markerClassName)) {
10245 return;
10246 }
10247 this._attachments(input, inst);
10248 input.addClass(this.markerClassName).keydown(this._doKeyDown).
10249 keypress(this._doKeyPress).keyup(this._doKeyUp);
10250 this._autoSize(inst);
10251 $.data(target, PROP_NAME, inst);
10252 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
10253 if( inst.settings.disabled ) {
10254 this._disableDatepicker( target );
10255 }
10256 },
10257
10258 /* Make attachments based on settings. */
10259 _attachments: function(input, inst) {
10260 var showOn, buttonText, buttonImage,
10261 appendText = this._get(inst, "appendText"),
10262 isRTL = this._get(inst, "isRTL");
10263
10264 if (inst.append) {
10265 inst.append.remove();
10266 }
10267 if (appendText) {
10268 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
10269 input[isRTL ? "before" : "after"](inst.append);
10270 }
10271
10272 input.unbind("focus", this._showDatepicker);
10273
10274 if (inst.trigger) {
10275 inst.trigger.remove();
10276 }
10277
10278 showOn = this._get(inst, "showOn");
10279 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
10280 input.focus(this._showDatepicker);
10281 }
10282 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
10283 buttonText = this._get(inst, "buttonText");
10284 buttonImage = this._get(inst, "buttonImage");
10285 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
10286 $("<img/>").addClass(this._triggerClass).
10287 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
10288 $("<button type='button'></button>").addClass(this._triggerClass).
10289 html(!buttonImage ? buttonText : $("<img/>").attr(
10290 { src:buttonImage, alt:buttonText, title:buttonText })));
10291 input[isRTL ? "before" : "after"](inst.trigger);
10292 inst.trigger.click(function() {
10293 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
10294 $.datepicker._hideDatepicker();
10295 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
10296 $.datepicker._hideDatepicker();
10297 $.datepicker._showDatepicker(input[0]);
10298 } else {
10299 $.datepicker._showDatepicker(input[0]);
10300 }
10301 return false;
10302 });
10303 }
10304 },
10305
10306 /* Apply the maximum length for the date format. */
10307 _autoSize: function(inst) {
10308 if (this._get(inst, "autoSize") && !inst.inline) {
10309 var findMax, max, maxI, i,
10310 date = new Date(2009, 12 - 1, 20), // Ensure double digits
10311 dateFormat = this._get(inst, "dateFormat");
10312
10313 if (dateFormat.match(/[DM]/)) {
10314 findMax = function(names) {
10315 max = 0;
10316 maxI = 0;
10317 for (i = 0; i < names.length; i++) {
10318 if (names[i].length > max) {
10319 max = names[i].length;
10320 maxI = i;
10321 }
10322 }
10323 return maxI;
10324 };
10325 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
10326 "monthNames" : "monthNamesShort"))));
10327 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
10328 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
10329 }
10330 inst.input.attr("size", this._formatDate(inst, date).length);
10331 }
10332 },
10333
10334 /* Attach an inline date picker to a div. */
10335 _inlineDatepicker: function(target, inst) {
10336 var divSpan = $(target);
10337 if (divSpan.hasClass(this.markerClassName)) {
10338 return;
10339 }
10340 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
10341 $.data(target, PROP_NAME, inst);
10342 this._setDate(inst, this._getDefaultDate(inst), true);
10343 this._updateDatepicker(inst);
10344 this._updateAlternate(inst);
10345 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
10346 if( inst.settings.disabled ) {
10347 this._disableDatepicker( target );
10348 }
10349 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
10350 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
10351 inst.dpDiv.css( "display", "block" );
10352 },
10353
10354 /* Pop-up the date picker in a "dialog" box.
10355 * @param input element - ignored
10356 * @param date string or Date - the initial date to display
10357 * @param onSelect function - the function to call when a date is selected
10358 * @param settings object - update the dialog date picker instance's settings (anonymous object)
10359 * @param pos int[2] - coordinates for the dialog's position within the screen or
10360 * event - with x/y coordinates or
10361 * leave empty for default (screen centre)
10362 * @return the manager object
10363 */
10364 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
10365 var id, browserWidth, browserHeight, scrollX, scrollY,
10366 inst = this._dialogInst; // internal instance
10367
10368 if (!inst) {
10369 this.uuid += 1;
10370 id = "dp" + this.uuid;
10371 this._dialogInput = $("<input type='text' id='" + id +
10372 "' style='position: absolute; top: -100px; width: 0px;'/>");
10373 this._dialogInput.keydown(this._doKeyDown);
10374 $("body").append(this._dialogInput);
10375 inst = this._dialogInst = this._newInst(this._dialogInput, false);
10376 inst.settings = {};
10377 $.data(this._dialogInput[0], PROP_NAME, inst);
10378 }
10379 extendRemove(inst.settings, settings || {});
10380 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
10381 this._dialogInput.val(date);
10382
10383 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
10384 if (!this._pos) {
10385 browserWidth = document.documentElement.clientWidth;
10386 browserHeight = document.documentElement.clientHeight;
10387 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
10388 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
10389 this._pos = // should use actual width/height below
10390 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
10391 }
10392
10393 // move input on screen for focus, but hidden behind dialog
10394 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
10395 inst.settings.onSelect = onSelect;
10396 this._inDialog = true;
10397 this.dpDiv.addClass(this._dialogClass);
10398 this._showDatepicker(this._dialogInput[0]);
10399 if ($.blockUI) {
10400 $.blockUI(this.dpDiv);
10401 }
10402 $.data(this._dialogInput[0], PROP_NAME, inst);
10403 return this;
10404 },
10405
10406 /* Detach a datepicker from its control.
10407 * @param target element - the target input field or division or span
10408 */
10409 _destroyDatepicker: function(target) {
10410 var nodeName,
10411 $target = $(target),
10412 inst = $.data(target, PROP_NAME);
10413
10414 if (!$target.hasClass(this.markerClassName)) {
10415 return;
10416 }
10417
10418 nodeName = target.nodeName.toLowerCase();
10419 $.removeData(target, PROP_NAME);
10420 if (nodeName === "input") {
10421 inst.append.remove();
10422 inst.trigger.remove();
10423 $target.removeClass(this.markerClassName).
10424 unbind("focus", this._showDatepicker).
10425 unbind("keydown", this._doKeyDown).
10426 unbind("keypress", this._doKeyPress).
10427 unbind("keyup", this._doKeyUp);
10428 } else if (nodeName === "div" || nodeName === "span") {
10429 $target.removeClass(this.markerClassName).empty();
10430 }
10431 },
10432
10433 /* Enable the date picker to a jQuery selection.
10434 * @param target element - the target input field or division or span
10435 */
10436 _enableDatepicker: function(target) {
10437 var nodeName, inline,
10438 $target = $(target),
10439 inst = $.data(target, PROP_NAME);
10440
10441 if (!$target.hasClass(this.markerClassName)) {
10442 return;
10443 }
10444
10445 nodeName = target.nodeName.toLowerCase();
10446 if (nodeName === "input") {
10447 target.disabled = false;
10448 inst.trigger.filter("button").
10449 each(function() { this.disabled = false; }).end().
10450 filter("img").css({opacity: "1.0", cursor: ""});
10451 } else if (nodeName === "div" || nodeName === "span") {
10452 inline = $target.children("." + this._inlineClass);
10453 inline.children().removeClass("ui-state-disabled");
10454 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
10455 prop("disabled", false);
10456 }
10457 this._disabledInputs = $.map(this._disabledInputs,
10458 function(value) { return (value === target ? null : value); }); // delete entry
10459 },
10460
10461 /* Disable the date picker to a jQuery selection.
10462 * @param target element - the target input field or division or span
10463 */
10464 _disableDatepicker: function(target) {
10465 var nodeName, inline,
10466 $target = $(target),
10467 inst = $.data(target, PROP_NAME);
10468
10469 if (!$target.hasClass(this.markerClassName)) {
10470 return;
10471 }
10472
10473 nodeName = target.nodeName.toLowerCase();
10474 if (nodeName === "input") {
10475 target.disabled = true;
10476 inst.trigger.filter("button").
10477 each(function() { this.disabled = true; }).end().
10478 filter("img").css({opacity: "0.5", cursor: "default"});
10479 } else if (nodeName === "div" || nodeName === "span") {
10480 inline = $target.children("." + this._inlineClass);
10481 inline.children().addClass("ui-state-disabled");
10482 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
10483 prop("disabled", true);
10484 }
10485 this._disabledInputs = $.map(this._disabledInputs,
10486 function(value) { return (value === target ? null : value); }); // delete entry
10487 this._disabledInputs[this._disabledInputs.length] = target;
10488 },
10489
10490 /* Is the first field in a jQuery collection disabled as a datepicker?
10491 * @param target element - the target input field or division or span
10492 * @return boolean - true if disabled, false if enabled
10493 */
10494 _isDisabledDatepicker: function(target) {
10495 if (!target) {
10496 return false;
10497 }
10498 for (var i = 0; i < this._disabledInputs.length; i++) {
10499 if (this._disabledInputs[i] === target) {
10500 return true;
10501 }
10502 }
10503 return false;
10504 },
10505
10506 /* Retrieve the instance data for the target control.
10507 * @param target element - the target input field or division or span
10508 * @return object - the associated instance data
10509 * @throws error if a jQuery problem getting data
10510 */
10511 _getInst: function(target) {
10512 try {
10513 return $.data(target, PROP_NAME);
10514 }
10515 catch (err) {
10516 throw "Missing instance data for this datepicker";
10517 }
10518 },
10519
10520 /* Update or retrieve the settings for a date picker attached to an input field or division.
10521 * @param target element - the target input field or division or span
10522 * @param name object - the new settings to update or
10523 * string - the name of the setting to change or retrieve,
10524 * when retrieving also "all" for all instance settings or
10525 * "defaults" for all global defaults
10526 * @param value any - the new value for the setting
10527 * (omit if above is an object or to retrieve a value)
10528 */
10529 _optionDatepicker: function(target, name, value) {
10530 var settings, date, minDate, maxDate,
10531 inst = this._getInst(target);
10532
10533 if (arguments.length === 2 && typeof name === "string") {
10534 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
10535 (inst ? (name === "all" ? $.extend({}, inst.settings) :
10536 this._get(inst, name)) : null));
10537 }
10538
10539 settings = name || {};
10540 if (typeof name === "string") {
10541 settings = {};
10542 settings[name] = value;
10543 }
10544
10545 if (inst) {
10546 if (this._curInst === inst) {
10547 this._hideDatepicker();
10548 }
10549
10550 date = this._getDateDatepicker(target, true);
10551 minDate = this._getMinMaxDate(inst, "min");
10552 maxDate = this._getMinMaxDate(inst, "max");
10553 extendRemove(inst.settings, settings);
10554 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
10555 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
10556 inst.settings.minDate = this._formatDate(inst, minDate);
10557 }
10558 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
10559 inst.settings.maxDate = this._formatDate(inst, maxDate);
10560 }
10561 if ( "disabled" in settings ) {
10562 if ( settings.disabled ) {
10563 this._disableDatepicker(target);
10564 } else {
10565 this._enableDatepicker(target);
10566 }
10567 }
10568 this._attachments($(target), inst);
10569 this._autoSize(inst);
10570 this._setDate(inst, date);
10571 this._updateAlternate(inst);
10572 this._updateDatepicker(inst);
10573 }
10574 },
10575
10576 // change method deprecated
10577 _changeDatepicker: function(target, name, value) {
10578 this._optionDatepicker(target, name, value);
10579 },
10580
10581 /* Redraw the date picker attached to an input field or division.
10582 * @param target element - the target input field or division or span
10583 */
10584 _refreshDatepicker: function(target) {
10585 var inst = this._getInst(target);
10586 if (inst) {
10587 this._updateDatepicker(inst);
10588 }
10589 },
10590
10591 /* Set the dates for a jQuery selection.
10592 * @param target element - the target input field or division or span
10593 * @param date Date - the new date
10594 */
10595 _setDateDatepicker: function(target, date) {
10596 var inst = this._getInst(target);
10597 if (inst) {
10598 this._setDate(inst, date);
10599 this._updateDatepicker(inst);
10600 this._updateAlternate(inst);
10601 }
10602 },
10603
10604 /* Get the date(s) for the first entry in a jQuery selection.
10605 * @param target element - the target input field or division or span
10606 * @param noDefault boolean - true if no default date is to be used
10607 * @return Date - the current date
10608 */
10609 _getDateDatepicker: function(target, noDefault) {
10610 var inst = this._getInst(target);
10611 if (inst && !inst.inline) {
10612 this._setDateFromField(inst, noDefault);
10613 }
10614 return (inst ? this._getDate(inst) : null);
10615 },
10616
10617 /* Handle keystrokes. */
10618 _doKeyDown: function(event) {
10619 var onSelect, dateStr, sel,
10620 inst = $.datepicker._getInst(event.target),
10621 handled = true,
10622 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
10623
10624 inst._keyEvent = true;
10625 if ($.datepicker._datepickerShowing) {
10626 switch (event.keyCode) {
10627 case 9: $.datepicker._hideDatepicker();
10628 handled = false;
10629 break; // hide on tab out
10630 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
10631 $.datepicker._currentClass + ")", inst.dpDiv);
10632 if (sel[0]) {
10633 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
10634 }
10635
10636 onSelect = $.datepicker._get(inst, "onSelect");
10637 if (onSelect) {
10638 dateStr = $.datepicker._formatDate(inst);
10639
10640 // trigger custom callback
10641 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
10642 } else {
10643 $.datepicker._hideDatepicker();
10644 }
10645
10646 return false; // don't submit the form
10647 case 27: $.datepicker._hideDatepicker();
10648 break; // hide on escape
10649 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
10650 -$.datepicker._get(inst, "stepBigMonths") :
10651 -$.datepicker._get(inst, "stepMonths")), "M");
10652 break; // previous month/year on page up/+ ctrl
10653 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
10654 +$.datepicker._get(inst, "stepBigMonths") :
10655 +$.datepicker._get(inst, "stepMonths")), "M");
10656 break; // next month/year on page down/+ ctrl
10657 case 35: if (event.ctrlKey || event.metaKey) {
10658 $.datepicker._clearDate(event.target);
10659 }
10660 handled = event.ctrlKey || event.metaKey;
10661 break; // clear on ctrl or command +end
10662 case 36: if (event.ctrlKey || event.metaKey) {
10663 $.datepicker._gotoToday(event.target);
10664 }
10665 handled = event.ctrlKey || event.metaKey;
10666 break; // current on ctrl or command +home
10667 case 37: if (event.ctrlKey || event.metaKey) {
10668 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
10669 }
10670 handled = event.ctrlKey || event.metaKey;
10671 // -1 day on ctrl or command +left
10672 if (event.originalEvent.altKey) {
10673 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
10674 -$.datepicker._get(inst, "stepBigMonths") :
10675 -$.datepicker._get(inst, "stepMonths")), "M");
10676 }
10677 // next month/year on alt +left on Mac
10678 break;
10679 case 38: if (event.ctrlKey || event.metaKey) {
10680 $.datepicker._adjustDate(event.target, -7, "D");
10681 }
10682 handled = event.ctrlKey || event.metaKey;
10683 break; // -1 week on ctrl or command +up
10684 case 39: if (event.ctrlKey || event.metaKey) {
10685 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
10686 }
10687 handled = event.ctrlKey || event.metaKey;
10688 // +1 day on ctrl or command +right
10689 if (event.originalEvent.altKey) {
10690 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
10691 +$.datepicker._get(inst, "stepBigMonths") :
10692 +$.datepicker._get(inst, "stepMonths")), "M");
10693 }
10694 // next month/year on alt +right
10695 break;
10696 case 40: if (event.ctrlKey || event.metaKey) {
10697 $.datepicker._adjustDate(event.target, +7, "D");
10698 }
10699 handled = event.ctrlKey || event.metaKey;
10700 break; // +1 week on ctrl or command +down
10701 default: handled = false;
10702 }
10703 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
10704 $.datepicker._showDatepicker(this);
10705 } else {
10706 handled = false;
10707 }
10708
10709 if (handled) {
10710 event.preventDefault();
10711 event.stopPropagation();
10712 }
10713 },
10714
10715 /* Filter entered characters - based on date format. */
10716 _doKeyPress: function(event) {
10717 var chars, chr,
10718 inst = $.datepicker._getInst(event.target);
10719
10720 if ($.datepicker._get(inst, "constrainInput")) {
10721 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
10722 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
10723 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
10724 }
10725 },
10726
10727 /* Synchronise manual entry and field/alternate field. */
10728 _doKeyUp: function(event) {
10729 var date,
10730 inst = $.datepicker._getInst(event.target);
10731
10732 if (inst.input.val() !== inst.lastVal) {
10733 try {
10734 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
10735 (inst.input ? inst.input.val() : null),
10736 $.datepicker._getFormatConfig(inst));
10737
10738 if (date) { // only if valid
10739 $.datepicker._setDateFromField(inst);
10740 $.datepicker._updateAlternate(inst);
10741 $.datepicker._updateDatepicker(inst);
10742 }
10743 }
10744 catch (err) {
10745 }
10746 }
10747 return true;
10748 },
10749
10750 /* Pop-up the date picker for a given input field.
10751 * If false returned from beforeShow event handler do not show.
10752 * @param input element - the input field attached to the date picker or
10753 * event - if triggered by focus
10754 */
10755 _showDatepicker: function(input) {
10756 input = input.target || input;
10757 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
10758 input = $("input", input.parentNode)[0];
10759 }
10760
10761 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
10762 return;
10763 }
10764
10765 var inst, beforeShow, beforeShowSettings, isFixed,
10766 offset, showAnim, duration;
10767
10768 inst = $.datepicker._getInst(input);
10769 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
10770 $.datepicker._curInst.dpDiv.stop(true, true);
10771 if ( inst && $.datepicker._datepickerShowing ) {
10772 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
10773 }
10774 }
10775
10776 beforeShow = $.datepicker._get(inst, "beforeShow");
10777 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
10778 if(beforeShowSettings === false){
10779 return;
10780 }
10781 extendRemove(inst.settings, beforeShowSettings);
10782
10783 inst.lastVal = null;
10784 $.datepicker._lastInput = input;
10785 $.datepicker._setDateFromField(inst);
10786
10787 if ($.datepicker._inDialog) { // hide cursor
10788 input.value = "";
10789 }
10790 if (!$.datepicker._pos) { // position below input
10791 $.datepicker._pos = $.datepicker._findPos(input);
10792 $.datepicker._pos[1] += input.offsetHeight; // add the height
10793 }
10794
10795 isFixed = false;
10796 $(input).parents().each(function() {
10797 isFixed |= $(this).css("position") === "fixed";
10798 return !isFixed;
10799 });
10800
10801 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
10802 $.datepicker._pos = null;
10803 //to avoid flashes on Firefox
10804 inst.dpDiv.empty();
10805 // determine sizing offscreen
10806 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
10807 $.datepicker._updateDatepicker(inst);
10808 // fix width for dynamic number of date pickers
10809 // and adjust position before showing
10810 offset = $.datepicker._checkOffset(inst, offset, isFixed);
10811 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
10812 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
10813 left: offset.left + "px", top: offset.top + "px"});
10814
10815 if (!inst.inline) {
10816 showAnim = $.datepicker._get(inst, "showAnim");
10817 duration = $.datepicker._get(inst, "duration");
10818 inst.dpDiv.zIndex($(input).zIndex()+1);
10819 $.datepicker._datepickerShowing = true;
10820
10821 if ( $.effects && $.effects.effect[ showAnim ] ) {
10822 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
10823 } else {
10824 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
10825 }
10826
10827 if ( $.datepicker._shouldFocusInput( inst ) ) {
10828 inst.input.focus();
10829 }
10830
10831 $.datepicker._curInst = inst;
10832 }
10833 },
10834
10835 /* Generate the date picker content. */
10836 _updateDatepicker: function(inst) {
10837 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
10838 instActive = inst; // for delegate hover events
10839 inst.dpDiv.empty().append(this._generateHTML(inst));
10840 this._attachHandlers(inst);
10841 inst.dpDiv.find("." + this._dayOverClass + " a").mouseover();
10842
10843 var origyearshtml,
10844 numMonths = this._getNumberOfMonths(inst),
10845 cols = numMonths[1],
10846 width = 17;
10847
10848 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
10849 if (cols > 1) {
10850 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
10851 }
10852 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
10853 "Class"]("ui-datepicker-multi");
10854 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
10855 "Class"]("ui-datepicker-rtl");
10856
10857 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
10858 inst.input.focus();
10859 }
10860
10861 // deffered render of the years select (to avoid flashes on Firefox)
10862 if( inst.yearshtml ){
10863 origyearshtml = inst.yearshtml;
10864 setTimeout(function(){
10865 //assure that inst.yearshtml didn't change.
10866 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
10867 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
10868 }
10869 origyearshtml = inst.yearshtml = null;
10870 }, 0);
10871 }
10872 },
10873
10874 // #6694 - don't focus the input if it's already focused
10875 // this breaks the change event in IE
10876 // Support: IE and jQuery <1.9
10877 _shouldFocusInput: function( inst ) {
10878 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
10879 },
10880
10881 /* Check positioning to remain on screen. */
10882 _checkOffset: function(inst, offset, isFixed) {
10883 var dpWidth = inst.dpDiv.outerWidth(),
10884 dpHeight = inst.dpDiv.outerHeight(),
10885 inputWidth = inst.input ? inst.input.outerWidth() : 0,
10886 inputHeight = inst.input ? inst.input.outerHeight() : 0,
10887 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
10888 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
10889
10890 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
10891 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
10892 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
10893
10894 // now check if datepicker is showing outside window viewport - move to a better place if so.
10895 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
10896 Math.abs(offset.left + dpWidth - viewWidth) : 0);
10897 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
10898 Math.abs(dpHeight + inputHeight) : 0);
10899
10900 return offset;
10901 },
10902
10903 /* Find an object's position on the screen. */
10904 _findPos: function(obj) {
10905 var position,
10906 inst = this._getInst(obj),
10907 isRTL = this._get(inst, "isRTL");
10908
10909 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
10910 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
10911 }
10912
10913 position = $(obj).offset();
10914 return [position.left, position.top];
10915 },
10916
10917 /* Hide the date picker from view.
10918 * @param input element - the input field attached to the date picker
10919 */
10920 _hideDatepicker: function(input) {
10921 var showAnim, duration, postProcess, onClose,
10922 inst = this._curInst;
10923
10924 if (!inst || (input && inst !== $.data(input, PROP_NAME))) {
10925 return;
10926 }
10927
10928 if (this._datepickerShowing) {
10929 showAnim = this._get(inst, "showAnim");
10930 duration = this._get(inst, "duration");
10931 postProcess = function() {
10932 $.datepicker._tidyDialog(inst);
10933 };
10934
10935 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
10936 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
10937 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
10938 } else {
10939 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
10940 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
10941 }
10942
10943 if (!showAnim) {
10944 postProcess();
10945 }
10946 this._datepickerShowing = false;
10947
10948 onClose = this._get(inst, "onClose");
10949 if (onClose) {
10950 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
10951 }
10952
10953 this._lastInput = null;
10954 if (this._inDialog) {
10955 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
10956 if ($.blockUI) {
10957 $.unblockUI();
10958 $("body").append(this.dpDiv);
10959 }
10960 }
10961 this._inDialog = false;
10962 }
10963 },
10964
10965 /* Tidy up after a dialog display. */
10966 _tidyDialog: function(inst) {
10967 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
10968 },
10969
10970 /* Close date picker if clicked elsewhere. */
10971 _checkExternalClick: function(event) {
10972 if (!$.datepicker._curInst) {
10973 return;
10974 }
10975
10976 var $target = $(event.target),
10977 inst = $.datepicker._getInst($target[0]);
10978
10979 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
10980 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
10981 !$target.hasClass($.datepicker.markerClassName) &&
10982 !$target.closest("." + $.datepicker._triggerClass).length &&
10983 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
10984 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
10985 $.datepicker._hideDatepicker();
10986 }
10987 },
10988
10989 /* Adjust one of the date sub-fields. */
10990 _adjustDate: function(id, offset, period) {
10991 var target = $(id),
10992 inst = this._getInst(target[0]);
10993
10994 if (this._isDisabledDatepicker(target[0])) {
10995 return;
10996 }
10997 this._adjustInstDate(inst, offset +
10998 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
10999 period);
11000 this._updateDatepicker(inst);
11001 },
11002
11003 /* Action for current link. */
11004 _gotoToday: function(id) {
11005 var date,
11006 target = $(id),
11007 inst = this._getInst(target[0]);
11008
11009 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
11010 inst.selectedDay = inst.currentDay;
11011 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
11012 inst.drawYear = inst.selectedYear = inst.currentYear;
11013 } else {
11014 date = new Date();
11015 inst.selectedDay = date.getDate();
11016 inst.drawMonth = inst.selectedMonth = date.getMonth();
11017 inst.drawYear = inst.selectedYear = date.getFullYear();
11018 }
11019 this._notifyChange(inst);
11020 this._adjustDate(target);
11021 },
11022
11023 /* Action for selecting a new month/year. */
11024 _selectMonthYear: function(id, select, period) {
11025 var target = $(id),
11026 inst = this._getInst(target[0]);
11027
11028 inst["selected" + (period === "M" ? "Month" : "Year")] =
11029 inst["draw" + (period === "M" ? "Month" : "Year")] =
11030 parseInt(select.options[select.selectedIndex].value,10);
11031
11032 this._notifyChange(inst);
11033 this._adjustDate(target);
11034 },
11035
11036 /* Action for selecting a day. */
11037 _selectDay: function(id, month, year, td) {
11038 var inst,
11039 target = $(id);
11040
11041 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
11042 return;
11043 }
11044
11045 inst = this._getInst(target[0]);
11046 inst.selectedDay = inst.currentDay = $("a", td).html();
11047 inst.selectedMonth = inst.currentMonth = month;
11048 inst.selectedYear = inst.currentYear = year;
11049 this._selectDate(id, this._formatDate(inst,
11050 inst.currentDay, inst.currentMonth, inst.currentYear));
11051 },
11052
11053 /* Erase the input field and hide the date picker. */
11054 _clearDate: function(id) {
11055 var target = $(id);
11056 this._selectDate(target, "");
11057 },
11058
11059 /* Update the input field with the selected date. */
11060 _selectDate: function(id, dateStr) {
11061 var onSelect,
11062 target = $(id),
11063 inst = this._getInst(target[0]);
11064
11065 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
11066 if (inst.input) {
11067 inst.input.val(dateStr);
11068 }
11069 this._updateAlternate(inst);
11070
11071 onSelect = this._get(inst, "onSelect");
11072 if (onSelect) {
11073 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
11074 } else if (inst.input) {
11075 inst.input.trigger("change"); // fire the change event
11076 }
11077
11078 if (inst.inline){
11079 this._updateDatepicker(inst);
11080 } else {
11081 this._hideDatepicker();
11082 this._lastInput = inst.input[0];
11083 if (typeof(inst.input[0]) !== "object") {
11084 inst.input.focus(); // restore focus
11085 }
11086 this._lastInput = null;
11087 }
11088 },
11089
11090 /* Update any alternate field to synchronise with the main field. */
11091 _updateAlternate: function(inst) {
11092 var altFormat, date, dateStr,
11093 altField = this._get(inst, "altField");
11094
11095 if (altField) { // update alternate field too
11096 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
11097 date = this._getDate(inst);
11098 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
11099 $(altField).each(function() { $(this).val(dateStr); });
11100 }
11101 },
11102
11103 /* Set as beforeShowDay function to prevent selection of weekends.
11104 * @param date Date - the date to customise
11105 * @return [boolean, string] - is this date selectable?, what is its CSS class?
11106 */
11107 noWeekends: function(date) {
11108 var day = date.getDay();
11109 return [(day > 0 && day < 6), ""];
11110 },
11111
11112 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
11113 * @param date Date - the date to get the week for
11114 * @return number - the number of the week within the year that contains this date
11115 */
11116 iso8601Week: function(date) {
11117 var time,
11118 checkDate = new Date(date.getTime());
11119
11120 // Find Thursday of this week starting on Monday
11121 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
11122
11123 time = checkDate.getTime();
11124 checkDate.setMonth(0); // Compare with Jan 1
11125 checkDate.setDate(1);
11126 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
11127 },
11128
11129 /* Parse a string value into a date object.
11130 * See formatDate below for the possible formats.
11131 *
11132 * @param format string - the expected format of the date
11133 * @param value string - the date in the above format
11134 * @param settings Object - attributes include:
11135 * shortYearCutoff number - the cutoff year for determining the century (optional)
11136 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
11137 * dayNames string[7] - names of the days from Sunday (optional)
11138 * monthNamesShort string[12] - abbreviated names of the months (optional)
11139 * monthNames string[12] - names of the months (optional)
11140 * @return Date - the extracted date value or null if value is blank
11141 */
11142 parseDate: function (format, value, settings) {
11143 if (format == null || value == null) {
11144 throw "Invalid arguments";
11145 }
11146
11147 value = (typeof value === "object" ? value.toString() : value + "");
11148 if (value === "") {
11149 return null;
11150 }
11151
11152 var iFormat, dim, extra,
11153 iValue = 0,
11154 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
11155 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
11156 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
11157 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
11158 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
11159 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
11160 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
11161 year = -1,
11162 month = -1,
11163 day = -1,
11164 doy = -1,
11165 literal = false,
11166 date,
11167 // Check whether a format character is doubled
11168 lookAhead = function(match) {
11169 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
11170 if (matches) {
11171 iFormat++;
11172 }
11173 return matches;
11174 },
11175 // Extract a number from the string value
11176 getNumber = function(match) {
11177 var isDoubled = lookAhead(match),
11178 size = (match === "@" ? 14 : (match === "!" ? 20 :
11179 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
11180 digits = new RegExp("^\\d{1," + size + "}"),
11181 num = value.substring(iValue).match(digits);
11182 if (!num) {
11183 throw "Missing number at position " + iValue;
11184 }
11185 iValue += num[0].length;
11186 return parseInt(num[0], 10);
11187 },
11188 // Extract a name from the string value and convert to an index
11189 getName = function(match, shortNames, longNames) {
11190 var index = -1,
11191 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
11192 return [ [k, v] ];
11193 }).sort(function (a, b) {
11194 return -(a[1].length - b[1].length);
11195 });
11196
11197 $.each(names, function (i, pair) {
11198 var name = pair[1];
11199 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
11200 index = pair[0];
11201 iValue += name.length;
11202 return false;
11203 }
11204 });
11205 if (index !== -1) {
11206 return index + 1;
11207 } else {
11208 throw "Unknown name at position " + iValue;
11209 }
11210 },
11211 // Confirm that a literal character matches the string value
11212 checkLiteral = function() {
11213 if (value.charAt(iValue) !== format.charAt(iFormat)) {
11214 throw "Unexpected literal at position " + iValue;
11215 }
11216 iValue++;
11217 };
11218
11219 for (iFormat = 0; iFormat < format.length; iFormat++) {
11220 if (literal) {
11221 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
11222 literal = false;
11223 } else {
11224 checkLiteral();
11225 }
11226 } else {
11227 switch (format.charAt(iFormat)) {
11228 case "d":
11229 day = getNumber("d");
11230 break;
11231 case "D":
11232 getName("D", dayNamesShort, dayNames);
11233 break;
11234 case "o":
11235 doy = getNumber("o");
11236 break;
11237 case "m":
11238 month = getNumber("m");
11239 break;
11240 case "M":
11241 month = getName("M", monthNamesShort, monthNames);
11242 break;
11243 case "y":
11244 year = getNumber("y");
11245 break;
11246 case "@":
11247 date = new Date(getNumber("@"));
11248 year = date.getFullYear();
11249 month = date.getMonth() + 1;
11250 day = date.getDate();
11251 break;
11252 case "!":
11253 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
11254 year = date.getFullYear();
11255 month = date.getMonth() + 1;
11256 day = date.getDate();
11257 break;
11258 case "'":
11259 if (lookAhead("'")){
11260 checkLiteral();
11261 } else {
11262 literal = true;
11263 }
11264 break;
11265 default:
11266 checkLiteral();
11267 }
11268 }
11269 }
11270
11271 if (iValue < value.length){
11272 extra = value.substr(iValue);
11273 if (!/^\s+/.test(extra)) {
11274 throw "Extra/unparsed characters found in date: " + extra;
11275 }
11276 }
11277
11278 if (year === -1) {
11279 year = new Date().getFullYear();
11280 } else if (year < 100) {
11281 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
11282 (year <= shortYearCutoff ? 0 : -100);
11283 }
11284
11285 if (doy > -1) {
11286 month = 1;
11287 day = doy;
11288 do {
11289 dim = this._getDaysInMonth(year, month - 1);
11290 if (day <= dim) {
11291 break;
11292 }
11293 month++;
11294 day -= dim;
11295 } while (true);
11296 }
11297
11298 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
11299 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
11300 throw "Invalid date"; // E.g. 31/02/00
11301 }
11302 return date;
11303 },
11304
11305 /* Standard date formats. */
11306 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
11307 COOKIE: "D, dd M yy",
11308 ISO_8601: "yy-mm-dd",
11309 RFC_822: "D, d M y",
11310 RFC_850: "DD, dd-M-y",
11311 RFC_1036: "D, d M y",
11312 RFC_1123: "D, d M yy",
11313 RFC_2822: "D, d M yy",
11314 RSS: "D, d M y", // RFC 822
11315 TICKS: "!",
11316 TIMESTAMP: "@",
11317 W3C: "yy-mm-dd", // ISO 8601
11318
11319 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
11320 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
11321
11322 /* Format a date object into a string value.
11323 * The format can be combinations of the following:
11324 * d - day of month (no leading zero)
11325 * dd - day of month (two digit)
11326 * o - day of year (no leading zeros)
11327 * oo - day of year (three digit)
11328 * D - day name short
11329 * DD - day name long
11330 * m - month of year (no leading zero)
11331 * mm - month of year (two digit)
11332 * M - month name short
11333 * MM - month name long
11334 * y - year (two digit)
11335 * yy - year (four digit)
11336 * @ - Unix timestamp (ms since 01/01/1970)
11337 * ! - Windows ticks (100ns since 01/01/0001)
11338 * "..." - literal text
11339 * '' - single quote
11340 *
11341 * @param format string - the desired format of the date
11342 * @param date Date - the date value to format
11343 * @param settings Object - attributes include:
11344 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
11345 * dayNames string[7] - names of the days from Sunday (optional)
11346 * monthNamesShort string[12] - abbreviated names of the months (optional)
11347 * monthNames string[12] - names of the months (optional)
11348 * @return string - the date in the above format
11349 */
11350 formatDate: function (format, date, settings) {
11351 if (!date) {
11352 return "";
11353 }
11354
11355 var iFormat,
11356 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
11357 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
11358 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
11359 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
11360 // Check whether a format character is doubled
11361 lookAhead = function(match) {
11362 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
11363 if (matches) {
11364 iFormat++;
11365 }
11366 return matches;
11367 },
11368 // Format a number, with leading zero if necessary
11369 formatNumber = function(match, value, len) {
11370 var num = "" + value;
11371 if (lookAhead(match)) {
11372 while (num.length < len) {
11373 num = "0" + num;
11374 }
11375 }
11376 return num;
11377 },
11378 // Format a name, short or long as requested
11379 formatName = function(match, value, shortNames, longNames) {
11380 return (lookAhead(match) ? longNames[value] : shortNames[value]);
11381 },
11382 output = "",
11383 literal = false;
11384
11385 if (date) {
11386 for (iFormat = 0; iFormat < format.length; iFormat++) {
11387 if (literal) {
11388 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
11389 literal = false;
11390 } else {
11391 output += format.charAt(iFormat);
11392 }
11393 } else {
11394 switch (format.charAt(iFormat)) {
11395 case "d":
11396 output += formatNumber("d", date.getDate(), 2);
11397 break;
11398 case "D":
11399 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
11400 break;
11401 case "o":
11402 output += formatNumber("o",
11403 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
11404 break;
11405 case "m":
11406 output += formatNumber("m", date.getMonth() + 1, 2);
11407 break;
11408 case "M":
11409 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
11410 break;
11411 case "y":
11412 output += (lookAhead("y") ? date.getFullYear() :
11413 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
11414 break;
11415 case "@":
11416 output += date.getTime();
11417 break;
11418 case "!":
11419 output += date.getTime() * 10000 + this._ticksTo1970;
11420 break;
11421 case "'":
11422 if (lookAhead("'")) {
11423 output += "'";
11424 } else {
11425 literal = true;
11426 }
11427 break;
11428 default:
11429 output += format.charAt(iFormat);
11430 }
11431 }
11432 }
11433 }
11434 return output;
11435 },
11436
11437 /* Extract all possible characters from the date format. */
11438 _possibleChars: function (format) {
11439 var iFormat,
11440 chars = "",
11441 literal = false,
11442 // Check whether a format character is doubled
11443 lookAhead = function(match) {
11444 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
11445 if (matches) {
11446 iFormat++;
11447 }
11448 return matches;
11449 };
11450
11451 for (iFormat = 0; iFormat < format.length; iFormat++) {
11452 if (literal) {
11453 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
11454 literal = false;
11455 } else {
11456 chars += format.charAt(iFormat);
11457 }
11458 } else {
11459 switch (format.charAt(iFormat)) {
11460 case "d": case "m": case "y": case "@":
11461 chars += "0123456789";
11462 break;
11463 case "D": case "M":
11464 return null; // Accept anything
11465 case "'":
11466 if (lookAhead("'")) {
11467 chars += "'";
11468 } else {
11469 literal = true;
11470 }
11471 break;
11472 default:
11473 chars += format.charAt(iFormat);
11474 }
11475 }
11476 }
11477 return chars;
11478 },
11479
11480 /* Get a setting value, defaulting if necessary. */
11481 _get: function(inst, name) {
11482 return inst.settings[name] !== undefined ?
11483 inst.settings[name] : this._defaults[name];
11484 },
11485
11486 /* Parse existing date and initialise date picker. */
11487 _setDateFromField: function(inst, noDefault) {
11488 if (inst.input.val() === inst.lastVal) {
11489 return;
11490 }
11491
11492 var dateFormat = this._get(inst, "dateFormat"),
11493 dates = inst.lastVal = inst.input ? inst.input.val() : null,
11494 defaultDate = this._getDefaultDate(inst),
11495 date = defaultDate,
11496 settings = this._getFormatConfig(inst);
11497
11498 try {
11499 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
11500 } catch (event) {
11501 dates = (noDefault ? "" : dates);
11502 }
11503 inst.selectedDay = date.getDate();
11504 inst.drawMonth = inst.selectedMonth = date.getMonth();
11505 inst.drawYear = inst.selectedYear = date.getFullYear();
11506 inst.currentDay = (dates ? date.getDate() : 0);
11507 inst.currentMonth = (dates ? date.getMonth() : 0);
11508 inst.currentYear = (dates ? date.getFullYear() : 0);
11509 this._adjustInstDate(inst);
11510 },
11511
11512 /* Retrieve the default date shown on opening. */
11513 _getDefaultDate: function(inst) {
11514 return this._restrictMinMax(inst,
11515 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
11516 },
11517
11518 /* A date may be specified as an exact value or a relative one. */
11519 _determineDate: function(inst, date, defaultDate) {
11520 var offsetNumeric = function(offset) {
11521 var date = new Date();
11522 date.setDate(date.getDate() + offset);
11523 return date;
11524 },
11525 offsetString = function(offset) {
11526 try {
11527 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
11528 offset, $.datepicker._getFormatConfig(inst));
11529 }
11530 catch (e) {
11531 // Ignore
11532 }
11533
11534 var date = (offset.toLowerCase().match(/^c/) ?
11535 $.datepicker._getDate(inst) : null) || new Date(),
11536 year = date.getFullYear(),
11537 month = date.getMonth(),
11538 day = date.getDate(),
11539 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
11540 matches = pattern.exec(offset);
11541
11542 while (matches) {
11543 switch (matches[2] || "d") {
11544 case "d" : case "D" :
11545 day += parseInt(matches[1],10); break;
11546 case "w" : case "W" :
11547 day += parseInt(matches[1],10) * 7; break;
11548 case "m" : case "M" :
11549 month += parseInt(matches[1],10);
11550 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
11551 break;
11552 case "y": case "Y" :
11553 year += parseInt(matches[1],10);
11554 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
11555 break;
11556 }
11557 matches = pattern.exec(offset);
11558 }
11559 return new Date(year, month, day);
11560 },
11561 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
11562 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
11563
11564 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
11565 if (newDate) {
11566 newDate.setHours(0);
11567 newDate.setMinutes(0);
11568 newDate.setSeconds(0);
11569 newDate.setMilliseconds(0);
11570 }
11571 return this._daylightSavingAdjust(newDate);
11572 },
11573
11574 /* Handle switch to/from daylight saving.
11575 * Hours may be non-zero on daylight saving cut-over:
11576 * > 12 when midnight changeover, but then cannot generate
11577 * midnight datetime, so jump to 1AM, otherwise reset.
11578 * @param date (Date) the date to check
11579 * @return (Date) the corrected date
11580 */
11581 _daylightSavingAdjust: function(date) {
11582 if (!date) {
11583 return null;
11584 }
11585 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
11586 return date;
11587 },
11588
11589 /* Set the date(s) directly. */
11590 _setDate: function(inst, date, noChange) {
11591 var clear = !date,
11592 origMonth = inst.selectedMonth,
11593 origYear = inst.selectedYear,
11594 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
11595
11596 inst.selectedDay = inst.currentDay = newDate.getDate();
11597 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
11598 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
11599 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
11600 this._notifyChange(inst);
11601 }
11602 this._adjustInstDate(inst);
11603 if (inst.input) {
11604 inst.input.val(clear ? "" : this._formatDate(inst));
11605 }
11606 },
11607
11608 /* Retrieve the date(s) directly. */
11609 _getDate: function(inst) {
11610 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
11611 this._daylightSavingAdjust(new Date(
11612 inst.currentYear, inst.currentMonth, inst.currentDay)));
11613 return startDate;
11614 },
11615
11616 /* Attach the onxxx handlers. These are declared statically so
11617 * they work with static code transformers like Caja.
11618 */
11619 _attachHandlers: function(inst) {
11620 var stepMonths = this._get(inst, "stepMonths"),
11621 id = "#" + inst.id.replace( /\\\\/g, "\\" );
11622 inst.dpDiv.find("[data-handler]").map(function () {
11623 var handler = {
11624 prev: function () {
11625 $.datepicker._adjustDate(id, -stepMonths, "M");
11626 },
11627 next: function () {
11628 $.datepicker._adjustDate(id, +stepMonths, "M");
11629 },
11630 hide: function () {
11631 $.datepicker._hideDatepicker();
11632 },
11633 today: function () {
11634 $.datepicker._gotoToday(id);
11635 },
11636 selectDay: function () {
11637 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
11638 return false;
11639 },
11640 selectMonth: function () {
11641 $.datepicker._selectMonthYear(id, this, "M");
11642 return false;
11643 },
11644 selectYear: function () {
11645 $.datepicker._selectMonthYear(id, this, "Y");
11646 return false;
11647 }
11648 };
11649 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
11650 });
11651 },
11652
11653 /* Generate the HTML for the current state of the date picker. */
11654 _generateHTML: function(inst) {
11655 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
11656 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
11657 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
11658 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
11659 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
11660 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
11661 tempDate = new Date(),
11662 today = this._daylightSavingAdjust(
11663 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
11664 isRTL = this._get(inst, "isRTL"),
11665 showButtonPanel = this._get(inst, "showButtonPanel"),
11666 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
11667 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
11668 numMonths = this._getNumberOfMonths(inst),
11669 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
11670 stepMonths = this._get(inst, "stepMonths"),
11671 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
11672 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
11673 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
11674 minDate = this._getMinMaxDate(inst, "min"),
11675 maxDate = this._getMinMaxDate(inst, "max"),
11676 drawMonth = inst.drawMonth - showCurrentAtPos,
11677 drawYear = inst.drawYear;
11678
11679 if (drawMonth < 0) {
11680 drawMonth += 12;
11681 drawYear--;
11682 }
11683 if (maxDate) {
11684 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
11685 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
11686 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
11687 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
11688 drawMonth--;
11689 if (drawMonth < 0) {
11690 drawMonth = 11;
11691 drawYear--;
11692 }
11693 }
11694 }
11695 inst.drawMonth = drawMonth;
11696 inst.drawYear = drawYear;
11697
11698 prevText = this._get(inst, "prevText");
11699 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
11700 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
11701 this._getFormatConfig(inst)));
11702
11703 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
11704 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
11705 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
11706 (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
11707
11708 nextText = this._get(inst, "nextText");
11709 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
11710 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
11711 this._getFormatConfig(inst)));
11712
11713 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
11714 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
11715 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
11716 (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
11717
11718 currentText = this._get(inst, "currentText");
11719 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
11720 currentText = (!navigationAsDateFormat ? currentText :
11721 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
11722
11723 controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
11724 this._get(inst, "closeText") + "</button>" : "");
11725
11726 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
11727 (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
11728 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
11729
11730 firstDay = parseInt(this._get(inst, "firstDay"),10);
11731 firstDay = (isNaN(firstDay) ? 0 : firstDay);
11732
11733 showWeek = this._get(inst, "showWeek");
11734 dayNames = this._get(inst, "dayNames");
11735 dayNamesMin = this._get(inst, "dayNamesMin");
11736 monthNames = this._get(inst, "monthNames");
11737 monthNamesShort = this._get(inst, "monthNamesShort");
11738 beforeShowDay = this._get(inst, "beforeShowDay");
11739 showOtherMonths = this._get(inst, "showOtherMonths");
11740 selectOtherMonths = this._get(inst, "selectOtherMonths");
11741 defaultDate = this._getDefaultDate(inst);
11742 html = "";
11743 dow;
11744 for (row = 0; row < numMonths[0]; row++) {
11745 group = "";
11746 this.maxRows = 4;
11747 for (col = 0; col < numMonths[1]; col++) {
11748 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
11749 cornerClass = " ui-corner-all";
11750 calender = "";
11751 if (isMultiMonth) {
11752 calender += "<div class='ui-datepicker-group";
11753 if (numMonths[1] > 1) {
11754 switch (col) {
11755 case 0: calender += " ui-datepicker-group-first";
11756 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
11757 case numMonths[1]-1: calender += " ui-datepicker-group-last";
11758 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
11759 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
11760 }
11761 }
11762 calender += "'>";
11763 }
11764 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
11765 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
11766 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
11767 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
11768 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
11769 "</div><table class='ui-datepicker-calendar'><thead>" +
11770 "<tr>";
11771 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
11772 for (dow = 0; dow < 7; dow++) { // days of the week
11773 day = (dow + firstDay) % 7;
11774 thead += "<th" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
11775 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
11776 }
11777 calender += thead + "</tr></thead><tbody>";
11778 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
11779 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
11780 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
11781 }
11782 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
11783 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
11784 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
11785 this.maxRows = numRows;
11786 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
11787 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
11788 calender += "<tr>";
11789 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
11790 this._get(inst, "calculateWeek")(printDate) + "</td>");
11791 for (dow = 0; dow < 7; dow++) { // create date picker days
11792 daySettings = (beforeShowDay ?
11793 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
11794 otherMonth = (printDate.getMonth() !== drawMonth);
11795 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
11796 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
11797 tbody += "<td class='" +
11798 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
11799 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
11800 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
11801 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
11802 // or defaultDate is current printedDate and defaultDate is selectedDate
11803 " " + this._dayOverClass : "") + // highlight selected day
11804 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
11805 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
11806 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
11807 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
11808 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
11809 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
11810 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
11811 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
11812 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
11813 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
11814 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
11815 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
11816 printDate.setDate(printDate.getDate() + 1);
11817 printDate = this._daylightSavingAdjust(printDate);
11818 }
11819 calender += tbody + "</tr>";
11820 }
11821 drawMonth++;
11822 if (drawMonth > 11) {
11823 drawMonth = 0;
11824 drawYear++;
11825 }
11826 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
11827 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
11828 group += calender;
11829 }
11830 html += group;
11831 }
11832 html += buttonPanel;
11833 inst._keyEvent = false;
11834 return html;
11835 },
11836
11837 /* Generate the month and year header. */
11838 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
11839 secondary, monthNames, monthNamesShort) {
11840
11841 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
11842 changeMonth = this._get(inst, "changeMonth"),
11843 changeYear = this._get(inst, "changeYear"),
11844 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
11845 html = "<div class='ui-datepicker-title'>",
11846 monthHtml = "";
11847
11848 // month selection
11849 if (secondary || !changeMonth) {
11850 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
11851 } else {
11852 inMinYear = (minDate && minDate.getFullYear() === drawYear);
11853 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
11854 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
11855 for ( month = 0; month < 12; month++) {
11856 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
11857 monthHtml += "<option value='" + month + "'" +
11858 (month === drawMonth ? " selected='selected'" : "") +
11859 ">" + monthNamesShort[month] + "</option>";
11860 }
11861 }
11862 monthHtml += "</select>";
11863 }
11864
11865 if (!showMonthAfterYear) {
11866 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
11867 }
11868
11869 // year selection
11870 if ( !inst.yearshtml ) {
11871 inst.yearshtml = "";
11872 if (secondary || !changeYear) {
11873 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
11874 } else {
11875 // determine range of years to display
11876 years = this._get(inst, "yearRange").split(":");
11877 thisYear = new Date().getFullYear();
11878 determineYear = function(value) {
11879 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
11880 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
11881 parseInt(value, 10)));
11882 return (isNaN(year) ? thisYear : year);
11883 };
11884 year = determineYear(years[0]);
11885 endYear = Math.max(year, determineYear(years[1] || ""));
11886 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
11887 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
11888 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
11889 for (; year <= endYear; year++) {
11890 inst.yearshtml += "<option value='" + year + "'" +
11891 (year === drawYear ? " selected='selected'" : "") +
11892 ">" + year + "</option>";
11893 }
11894 inst.yearshtml += "</select>";
11895
11896 html += inst.yearshtml;
11897 inst.yearshtml = null;
11898 }
11899 }
11900
11901 html += this._get(inst, "yearSuffix");
11902 if (showMonthAfterYear) {
11903 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
11904 }
11905 html += "</div>"; // Close datepicker_header
11906 return html;
11907 },
11908
11909 /* Adjust one of the date sub-fields. */
11910 _adjustInstDate: function(inst, offset, period) {
11911 var year = inst.drawYear + (period === "Y" ? offset : 0),
11912 month = inst.drawMonth + (period === "M" ? offset : 0),
11913 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
11914 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
11915
11916 inst.selectedDay = date.getDate();
11917 inst.drawMonth = inst.selectedMonth = date.getMonth();
11918 inst.drawYear = inst.selectedYear = date.getFullYear();
11919 if (period === "M" || period === "Y") {
11920 this._notifyChange(inst);
11921 }
11922 },
11923
11924 /* Ensure a date is within any min/max bounds. */
11925 _restrictMinMax: function(inst, date) {
11926 var minDate = this._getMinMaxDate(inst, "min"),
11927 maxDate = this._getMinMaxDate(inst, "max"),
11928 newDate = (minDate && date < minDate ? minDate : date);
11929 return (maxDate && newDate > maxDate ? maxDate : newDate);
11930 },
11931
11932 /* Notify change of month/year. */
11933 _notifyChange: function(inst) {
11934 var onChange = this._get(inst, "onChangeMonthYear");
11935 if (onChange) {
11936 onChange.apply((inst.input ? inst.input[0] : null),
11937 [inst.selectedYear, inst.selectedMonth + 1, inst]);
11938 }
11939 },
11940
11941 /* Determine the number of months to show. */
11942 _getNumberOfMonths: function(inst) {
11943 var numMonths = this._get(inst, "numberOfMonths");
11944 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
11945 },
11946
11947 /* Determine the current maximum date - ensure no time components are set. */
11948 _getMinMaxDate: function(inst, minMax) {
11949 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
11950 },
11951
11952 /* Find the number of days in a given month. */
11953 _getDaysInMonth: function(year, month) {
11954 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
11955 },
11956
11957 /* Find the day of the week of the first of a month. */
11958 _getFirstDayOfMonth: function(year, month) {
11959 return new Date(year, month, 1).getDay();
11960 },
11961
11962 /* Determines if we should allow a "next/prev" month display change. */
11963 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
11964 var numMonths = this._getNumberOfMonths(inst),
11965 date = this._daylightSavingAdjust(new Date(curYear,
11966 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
11967
11968 if (offset < 0) {
11969 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
11970 }
11971 return this._isInRange(inst, date);
11972 },
11973
11974 /* Is the given date in the accepted range? */
11975 _isInRange: function(inst, date) {
11976 var yearSplit, currentYear,
11977 minDate = this._getMinMaxDate(inst, "min"),
11978 maxDate = this._getMinMaxDate(inst, "max"),
11979 minYear = null,
11980 maxYear = null,
11981 years = this._get(inst, "yearRange");
11982 if (years){
11983 yearSplit = years.split(":");
11984 currentYear = new Date().getFullYear();
11985 minYear = parseInt(yearSplit[0], 10);
11986 maxYear = parseInt(yearSplit[1], 10);
11987 if ( yearSplit[0].match(/[+\-].*/) ) {
11988 minYear += currentYear;
11989 }
11990 if ( yearSplit[1].match(/[+\-].*/) ) {
11991 maxYear += currentYear;
11992 }
11993 }
11994
11995 return ((!minDate || date.getTime() >= minDate.getTime()) &&
11996 (!maxDate || date.getTime() <= maxDate.getTime()) &&
11997 (!minYear || date.getFullYear() >= minYear) &&
11998 (!maxYear || date.getFullYear() <= maxYear));
11999 },
12000
12001 /* Provide the configuration settings for formatting/parsing. */
12002 _getFormatConfig: function(inst) {
12003 var shortYearCutoff = this._get(inst, "shortYearCutoff");
12004 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
12005 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
12006 return {shortYearCutoff: shortYearCutoff,
12007 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
12008 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
12009 },
12010
12011 /* Format the given date for display. */
12012 _formatDate: function(inst, day, month, year) {
12013 if (!day) {
12014 inst.currentDay = inst.selectedDay;
12015 inst.currentMonth = inst.selectedMonth;
12016 inst.currentYear = inst.selectedYear;
12017 }
12018 var date = (day ? (typeof day === "object" ? day :
12019 this._daylightSavingAdjust(new Date(year, month, day))) :
12020 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
12021 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
12022 }
12023 });
12024
12025 /*
12026 * Bind hover events for datepicker elements.
12027 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
12028 * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
12029 */
12030 function bindHover(dpDiv) {
12031 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
12032 return dpDiv.delegate(selector, "mouseout", function() {
12033 $(this).removeClass("ui-state-hover");
12034 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
12035 $(this).removeClass("ui-datepicker-prev-hover");
12036 }
12037 if (this.className.indexOf("ui-datepicker-next") !== -1) {
12038 $(this).removeClass("ui-datepicker-next-hover");
12039 }
12040 })
12041 .delegate(selector, "mouseover", function(){
12042 if (!$.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0])) {
12043 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
12044 $(this).addClass("ui-state-hover");
12045 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
12046 $(this).addClass("ui-datepicker-prev-hover");
12047 }
12048 if (this.className.indexOf("ui-datepicker-next") !== -1) {
12049 $(this).addClass("ui-datepicker-next-hover");
12050 }
12051 }
12052 });
12053 }
12054
12055 /* jQuery extend now ignores nulls! */
12056 function extendRemove(target, props) {
12057 $.extend(target, props);
12058 for (var name in props) {
12059 if (props[name] == null) {
12060 target[name] = props[name];
12061 }
12062 }
12063 return target;
12064 }
12065
12066 /* Invoke the datepicker functionality.
12067 @param options string - a command, optionally followed by additional parameters or
12068 Object - settings for attaching new datepicker functionality
12069 @return jQuery object */
12070 $.fn.datepicker = function(options){
12071
12072 /* Verify an empty collection wasn't passed - Fixes #6976 */
12073 if ( !this.length ) {
12074 return this;
12075 }
12076
12077 /* Initialise the date picker. */
12078 if (!$.datepicker.initialized) {
12079 $(document).mousedown($.datepicker._checkExternalClick);
12080 $.datepicker.initialized = true;
12081 }
12082
12083 /* Append datepicker main container to body if not exist. */
12084 if ($("#"+$.datepicker._mainDivId).length === 0) {
12085 $("body").append($.datepicker.dpDiv);
12086 }
12087
12088 var otherArgs = Array.prototype.slice.call(arguments, 1);
12089 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
12090 return $.datepicker["_" + options + "Datepicker"].
12091 apply($.datepicker, [this[0]].concat(otherArgs));
12092 }
12093 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
12094 return $.datepicker["_" + options + "Datepicker"].
12095 apply($.datepicker, [this[0]].concat(otherArgs));
12096 }
12097 return this.each(function() {
12098 typeof options === "string" ?
12099 $.datepicker["_" + options + "Datepicker"].
12100 apply($.datepicker, [this].concat(otherArgs)) :
12101 $.datepicker._attachDatepicker(this, options);
12102 });
12103 };
12104
12105 $.datepicker = new Datepicker(); // singleton instance
12106 $.datepicker.initialized = false;
12107 $.datepicker.uuid = new Date().getTime();
12108 $.datepicker.version = "1.10.3";
12109
12110 })(jQuery);
12111 (function( $, undefined ) {
12112
12113 var sizeRelatedOptions = {
12114 buttons: true,
12115 height: true,
12116 maxHeight: true,
12117 maxWidth: true,
12118 minHeight: true,
12119 minWidth: true,
12120 width: true
12121 },
12122 resizableRelatedOptions = {
12123 maxHeight: true,
12124 maxWidth: true,
12125 minHeight: true,
12126 minWidth: true
12127 };
12128
12129 $.widget( "ui.dialog", {
12130 version: "1.10.3",
12131 options: {
12132 appendTo: "body",
12133 autoOpen: true,
12134 buttons: [],
12135 closeOnEscape: true,
12136 closeText: "close",
12137 dialogClass: "",
12138 draggable: true,
12139 hide: null,
12140 height: "auto",
12141 maxHeight: null,
12142 maxWidth: null,
12143 minHeight: 150,
12144 minWidth: 150,
12145 modal: false,
12146 position: {
12147 my: "center",
12148 at: "center",
12149 of: window,
12150 collision: "fit",
12151 // Ensure the titlebar is always visible
12152 using: function( pos ) {
12153 var topOffset = $( this ).css( pos ).offset().top;
12154 if ( topOffset < 0 ) {
12155 $( this ).css( "top", pos.top - topOffset );
12156 }
12157 }
12158 },
12159 resizable: true,
12160 show: null,
12161 title: null,
12162 width: 300,
12163
12164 // callbacks
12165 beforeClose: null,
12166 close: null,
12167 drag: null,
12168 dragStart: null,
12169 dragStop: null,
12170 focus: null,
12171 open: null,
12172 resize: null,
12173 resizeStart: null,
12174 resizeStop: null
12175 },
12176
12177 _create: function() {
12178 this.originalCss = {
12179 display: this.element[0].style.display,
12180 width: this.element[0].style.width,
12181 minHeight: this.element[0].style.minHeight,
12182 maxHeight: this.element[0].style.maxHeight,
12183 height: this.element[0].style.height
12184 };
12185 this.originalPosition = {
12186 parent: this.element.parent(),
12187 index: this.element.parent().children().index( this.element )
12188 };
12189 this.originalTitle = this.element.attr("title");
12190 this.options.title = this.options.title || this.originalTitle;
12191
12192 this._createWrapper();
12193
12194 this.element
12195 .show()
12196 .removeAttr("title")
12197 .addClass("ui-dialog-content ui-widget-content")
12198 .appendTo( this.uiDialog );
12199
12200 this._createTitlebar();
12201 this._createButtonPane();
12202
12203 if ( this.options.draggable && $.fn.draggable ) {
12204 this._makeDraggable();
12205 }
12206 if ( this.options.resizable && $.fn.resizable ) {
12207 this._makeResizable();
12208 }
12209
12210 this._isOpen = false;
12211 },
12212
12213 _init: function() {
12214 if ( this.options.autoOpen ) {
12215 this.open();
12216 }
12217 },
12218
12219 _appendTo: function() {
12220 var element = this.options.appendTo;
12221 if ( element && (element.jquery || element.nodeType) ) {
12222 return $( element );
12223 }
12224 return this.document.find( element || "body" ).eq( 0 );
12225 },
12226
12227 _destroy: function() {
12228 var next,
12229 originalPosition = this.originalPosition;
12230
12231 this._destroyOverlay();
12232
12233 this.element
12234 .removeUniqueId()
12235 .removeClass("ui-dialog-content ui-widget-content")
12236 .css( this.originalCss )
12237 // Without detaching first, the following becomes really slow
12238 .detach();
12239
12240 this.uiDialog.stop( true, true ).remove();
12241
12242 if ( this.originalTitle ) {
12243 this.element.attr( "title", this.originalTitle );
12244 }
12245
12246 next = originalPosition.parent.children().eq( originalPosition.index );
12247 // Don't try to place the dialog next to itself (#8613)
12248 if ( next.length && next[0] !== this.element[0] ) {
12249 next.before( this.element );
12250 } else {
12251 originalPosition.parent.append( this.element );
12252 }
12253 },
12254
12255 widget: function() {
12256 return this.uiDialog;
12257 },
12258
12259 disable: $.noop,
12260 enable: $.noop,
12261
12262 close: function( event ) {
12263 var that = this;
12264
12265 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
12266 return;
12267 }
12268
12269 this._isOpen = false;
12270 this._destroyOverlay();
12271
12272 if ( !this.opener.filter(":focusable").focus().length ) {
12273 // Hiding a focused element doesn't trigger blur in WebKit
12274 // so in case we have nothing to focus on, explicitly blur the active element
12275 // https://bugs.webkit.org/show_bug.cgi?id=47182
12276 $( this.document[0].activeElement ).blur();
12277 }
12278
12279 this._hide( this.uiDialog, this.options.hide, function() {
12280 that._trigger( "close", event );
12281 });
12282 },
12283
12284 isOpen: function() {
12285 return this._isOpen;
12286 },
12287
12288 moveToTop: function() {
12289 this._moveToTop();
12290 },
12291
12292 _moveToTop: function( event, silent ) {
12293 var moved = !!this.uiDialog.nextAll(":visible").insertBefore( this.uiDialog ).length;
12294 if ( moved && !silent ) {
12295 this._trigger( "focus", event );
12296 }
12297 return moved;
12298 },
12299
12300 open: function() {
12301 var that = this;
12302 if ( this._isOpen ) {
12303 if ( this._moveToTop() ) {
12304 this._focusTabbable();
12305 }
12306 return;
12307 }
12308
12309 this._isOpen = true;
12310 this.opener = $( this.document[0].activeElement );
12311
12312 this._size();
12313 this._position();
12314 this._createOverlay();
12315 this._moveToTop( null, true );
12316 this._show( this.uiDialog, this.options.show, function() {
12317 that._focusTabbable();
12318 that._trigger("focus");
12319 });
12320
12321 this._trigger("open");
12322 },
12323
12324 _focusTabbable: function() {
12325 // Set focus to the first match:
12326 // 1. First element inside the dialog matching [autofocus]
12327 // 2. Tabbable element inside the content element
12328 // 3. Tabbable element inside the buttonpane
12329 // 4. The close button
12330 // 5. The dialog itself
12331 var hasFocus = this.element.find("[autofocus]");
12332 if ( !hasFocus.length ) {
12333 hasFocus = this.element.find(":tabbable");
12334 }
12335 if ( !hasFocus.length ) {
12336 hasFocus = this.uiDialogButtonPane.find(":tabbable");
12337 }
12338 if ( !hasFocus.length ) {
12339 hasFocus = this.uiDialogTitlebarClose.filter(":tabbable");
12340 }
12341 if ( !hasFocus.length ) {
12342 hasFocus = this.uiDialog;
12343 }
12344 hasFocus.eq( 0 ).focus();
12345 },
12346
12347 _keepFocus: function( event ) {
12348 function checkFocus() {
12349 var activeElement = this.document[0].activeElement,
12350 isActive = this.uiDialog[0] === activeElement ||
12351 $.contains( this.uiDialog[0], activeElement );
12352 if ( !isActive ) {
12353 this._focusTabbable();
12354 }
12355 }
12356 event.preventDefault();
12357 checkFocus.call( this );
12358 // support: IE
12359 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
12360 // so we check again later
12361 this._delay( checkFocus );
12362 },
12363
12364 _createWrapper: function() {
12365 this.uiDialog = $("<div>")
12366 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
12367 this.options.dialogClass )
12368 .hide()
12369 .attr({
12370 // Setting tabIndex makes the div focusable
12371 tabIndex: -1,
12372 role: "dialog"
12373 })
12374 .appendTo( this._appendTo() );
12375
12376 this._on( this.uiDialog, {
12377 keydown: function( event ) {
12378 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
12379 event.keyCode === $.ui.keyCode.ESCAPE ) {
12380 event.preventDefault();
12381 this.close( event );
12382 return;
12383 }
12384
12385 // prevent tabbing out of dialogs
12386 if ( event.keyCode !== $.ui.keyCode.TAB ) {
12387 return;
12388 }
12389 var tabbables = this.uiDialog.find(":tabbable"),
12390 first = tabbables.filter(":first"),
12391 last = tabbables.filter(":last");
12392
12393 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
12394 first.focus( 1 );
12395 event.preventDefault();
12396 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
12397 last.focus( 1 );
12398 event.preventDefault();
12399 }
12400 },
12401 mousedown: function( event ) {
12402 if ( this._moveToTop( event ) ) {
12403 this._focusTabbable();
12404 }
12405 }
12406 });
12407
12408 // We assume that any existing aria-describedby attribute means
12409 // that the dialog content is marked up properly
12410 // otherwise we brute force the content as the description
12411 if ( !this.element.find("[aria-describedby]").length ) {
12412 this.uiDialog.attr({
12413 "aria-describedby": this.element.uniqueId().attr("id")
12414 });
12415 }
12416 },
12417
12418 _createTitlebar: function() {
12419 var uiDialogTitle;
12420
12421 this.uiDialogTitlebar = $("<div>")
12422 .addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix")
12423 .prependTo( this.uiDialog );
12424 this._on( this.uiDialogTitlebar, {
12425 mousedown: function( event ) {
12426 // Don't prevent click on close button (#8838)
12427 // Focusing a dialog that is partially scrolled out of view
12428 // causes the browser to scroll it into view, preventing the click event
12429 if ( !$( event.target ).closest(".ui-dialog-titlebar-close") ) {
12430 // Dialog isn't getting focus when dragging (#8063)
12431 this.uiDialog.focus();
12432 }
12433 }
12434 });
12435
12436 this.uiDialogTitlebarClose = $("<button></button>")
12437 .button({
12438 label: this.options.closeText,
12439 icons: {
12440 primary: "ui-icon-closethick"
12441 },
12442 text: false
12443 })
12444 .addClass("ui-dialog-titlebar-close")
12445 .appendTo( this.uiDialogTitlebar );
12446 this._on( this.uiDialogTitlebarClose, {
12447 click: function( event ) {
12448 event.preventDefault();
12449 this.close( event );
12450 }
12451 });
12452
12453 uiDialogTitle = $("<span>")
12454 .uniqueId()
12455 .addClass("ui-dialog-title")
12456 .prependTo( this.uiDialogTitlebar );
12457 this._title( uiDialogTitle );
12458
12459 this.uiDialog.attr({
12460 "aria-labelledby": uiDialogTitle.attr("id")
12461 });
12462 },
12463
12464 _title: function( title ) {
12465 if ( !this.options.title ) {
12466 title.html("&#160;");
12467 }
12468 title.text( this.options.title );
12469 },
12470
12471 _createButtonPane: function() {
12472 this.uiDialogButtonPane = $("<div>")
12473 .addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");
12474
12475 this.uiButtonSet = $("<div>")
12476 .addClass("ui-dialog-buttonset")
12477 .appendTo( this.uiDialogButtonPane );
12478
12479 this._createButtons();
12480 },
12481
12482 _createButtons: function() {
12483 var that = this,
12484 buttons = this.options.buttons;
12485
12486 // if we already have a button pane, remove it
12487 this.uiDialogButtonPane.remove();
12488 this.uiButtonSet.empty();
12489
12490 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
12491 this.uiDialog.removeClass("ui-dialog-buttons");
12492 return;
12493 }
12494
12495 $.each( buttons, function( name, props ) {
12496 var click, buttonOptions;
12497 props = $.isFunction( props ) ?
12498 { click: props, text: name } :
12499 props;
12500 // Default to a non-submitting button
12501 props = $.extend( { type: "button" }, props );
12502 // Change the context for the click callback to be the main element
12503 click = props.click;
12504 props.click = function() {
12505 click.apply( that.element[0], arguments );
12506 };
12507 buttonOptions = {
12508 icons: props.icons,
12509 text: props.showText
12510 };
12511 delete props.icons;
12512 delete props.showText;
12513 $( "<button></button>", props )
12514 .button( buttonOptions )
12515 .appendTo( that.uiButtonSet );
12516 });
12517 this.uiDialog.addClass("ui-dialog-buttons");
12518 this.uiDialogButtonPane.appendTo( this.uiDialog );
12519 },
12520
12521 _makeDraggable: function() {
12522 var that = this,
12523 options = this.options;
12524
12525 function filteredUi( ui ) {
12526 return {
12527 position: ui.position,
12528 offset: ui.offset
12529 };
12530 }
12531
12532 this.uiDialog.draggable({
12533 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
12534 handle: ".ui-dialog-titlebar",
12535 containment: "document",
12536 start: function( event, ui ) {
12537 $( this ).addClass("ui-dialog-dragging");
12538 that._blockFrames();
12539 that._trigger( "dragStart", event, filteredUi( ui ) );
12540 },
12541 drag: function( event, ui ) {
12542 that._trigger( "drag", event, filteredUi( ui ) );
12543 },
12544 stop: function( event, ui ) {
12545 options.position = [
12546 ui.position.left - that.document.scrollLeft(),
12547 ui.position.top - that.document.scrollTop()
12548 ];
12549 $( this ).removeClass("ui-dialog-dragging");
12550 that._unblockFrames();
12551 that._trigger( "dragStop", event, filteredUi( ui ) );
12552 }
12553 });
12554 },
12555
12556 _makeResizable: function() {
12557 var that = this,
12558 options = this.options,
12559 handles = options.resizable,
12560 // .ui-resizable has position: relative defined in the stylesheet
12561 // but dialogs have to use absolute or fixed positioning
12562 position = this.uiDialog.css("position"),
12563 resizeHandles = typeof handles === "string" ?
12564 handles :
12565 "n,e,s,w,se,sw,ne,nw";
12566
12567 function filteredUi( ui ) {
12568 return {
12569 originalPosition: ui.originalPosition,
12570 originalSize: ui.originalSize,
12571 position: ui.position,
12572 size: ui.size
12573 };
12574 }
12575
12576 this.uiDialog.resizable({
12577 cancel: ".ui-dialog-content",
12578 containment: "document",
12579 alsoResize: this.element,
12580 maxWidth: options.maxWidth,
12581 maxHeight: options.maxHeight,
12582 minWidth: options.minWidth,
12583 minHeight: this._minHeight(),
12584 handles: resizeHandles,
12585 start: function( event, ui ) {
12586 $( this ).addClass("ui-dialog-resizing");
12587 that._blockFrames();
12588 that._trigger( "resizeStart", event, filteredUi( ui ) );
12589 },
12590 resize: function( event, ui ) {
12591 that._trigger( "resize", event, filteredUi( ui ) );
12592 },
12593 stop: function( event, ui ) {
12594 options.height = $( this ).height();
12595 options.width = $( this ).width();
12596 $( this ).removeClass("ui-dialog-resizing");
12597 that._unblockFrames();
12598 that._trigger( "resizeStop", event, filteredUi( ui ) );
12599 }
12600 })
12601 .css( "position", position );
12602 },
12603
12604 _minHeight: function() {
12605 var options = this.options;
12606
12607 return options.height === "auto" ?
12608 options.minHeight :
12609 Math.min( options.minHeight, options.height );
12610 },
12611
12612 _position: function() {
12613 // Need to show the dialog to get the actual offset in the position plugin
12614 var isVisible = this.uiDialog.is(":visible");
12615 if ( !isVisible ) {
12616 this.uiDialog.show();
12617 }
12618 this.uiDialog.position( this.options.position );
12619 if ( !isVisible ) {
12620 this.uiDialog.hide();
12621 }
12622 },
12623
12624 _setOptions: function( options ) {
12625 var that = this,
12626 resize = false,
12627 resizableOptions = {};
12628
12629 $.each( options, function( key, value ) {
12630 that._setOption( key, value );
12631
12632 if ( key in sizeRelatedOptions ) {
12633 resize = true;
12634 }
12635 if ( key in resizableRelatedOptions ) {
12636 resizableOptions[ key ] = value;
12637 }
12638 });
12639
12640 if ( resize ) {
12641 this._size();
12642 this._position();
12643 }
12644 if ( this.uiDialog.is(":data(ui-resizable)") ) {
12645 this.uiDialog.resizable( "option", resizableOptions );
12646 }
12647 },
12648
12649 _setOption: function( key, value ) {
12650 /*jshint maxcomplexity:15*/
12651 var isDraggable, isResizable,
12652 uiDialog = this.uiDialog;
12653
12654 if ( key === "dialogClass" ) {
12655 uiDialog
12656 .removeClass( this.options.dialogClass )
12657 .addClass( value );
12658 }
12659
12660 if ( key === "disabled" ) {
12661 return;
12662 }
12663
12664 this._super( key, value );
12665
12666 if ( key === "appendTo" ) {
12667 this.uiDialog.appendTo( this._appendTo() );
12668 }
12669
12670 if ( key === "buttons" ) {
12671 this._createButtons();
12672 }
12673
12674 if ( key === "closeText" ) {
12675 this.uiDialogTitlebarClose.button({
12676 // Ensure that we always pass a string
12677 label: "" + value
12678 });
12679 }
12680
12681 if ( key === "draggable" ) {
12682 isDraggable = uiDialog.is(":data(ui-draggable)");
12683 if ( isDraggable && !value ) {
12684 uiDialog.draggable("destroy");
12685 }
12686
12687 if ( !isDraggable && value ) {
12688 this._makeDraggable();
12689 }
12690 }
12691
12692 if ( key === "position" ) {
12693 this._position();
12694 }
12695
12696 if ( key === "resizable" ) {
12697 // currently resizable, becoming non-resizable
12698 isResizable = uiDialog.is(":data(ui-resizable)");
12699 if ( isResizable && !value ) {
12700 uiDialog.resizable("destroy");
12701 }
12702
12703 // currently resizable, changing handles
12704 if ( isResizable && typeof value === "string" ) {
12705 uiDialog.resizable( "option", "handles", value );
12706 }
12707
12708 // currently non-resizable, becoming resizable
12709 if ( !isResizable && value !== false ) {
12710 this._makeResizable();
12711 }
12712 }
12713
12714 if ( key === "title" ) {
12715 this._title( this.uiDialogTitlebar.find(".ui-dialog-title") );
12716 }
12717 },
12718
12719 _size: function() {
12720 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
12721 // divs will both have width and height set, so we need to reset them
12722 var nonContentHeight, minContentHeight, maxContentHeight,
12723 options = this.options;
12724
12725 // Reset content sizing
12726 this.element.show().css({
12727 width: "auto",
12728 minHeight: 0,
12729 maxHeight: "none",
12730 height: 0
12731 });
12732
12733 if ( options.minWidth > options.width ) {
12734 options.width = options.minWidth;
12735 }
12736
12737 // reset wrapper sizing
12738 // determine the height of all the non-content elements
12739 nonContentHeight = this.uiDialog.css({
12740 height: "auto",
12741 width: options.width
12742 })
12743 .outerHeight();
12744 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
12745 maxContentHeight = typeof options.maxHeight === "number" ?
12746 Math.max( 0, options.maxHeight - nonContentHeight ) :
12747 "none";
12748
12749 if ( options.height === "auto" ) {
12750 this.element.css({
12751 minHeight: minContentHeight,
12752 maxHeight: maxContentHeight,
12753 height: "auto"
12754 });
12755 } else {
12756 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
12757 }
12758
12759 if (this.uiDialog.is(":data(ui-resizable)") ) {
12760 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
12761 }
12762 },
12763
12764 _blockFrames: function() {
12765 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
12766 var iframe = $( this );
12767
12768 return $( "<div>" )
12769 .css({
12770 position: "absolute",
12771 width: iframe.outerWidth(),
12772 height: iframe.outerHeight()
12773 })
12774 .appendTo( iframe.parent() )
12775 .offset( iframe.offset() )[0];
12776 });
12777 },
12778
12779 _unblockFrames: function() {
12780 if ( this.iframeBlocks ) {
12781 this.iframeBlocks.remove();
12782 delete this.iframeBlocks;
12783 }
12784 },
12785
12786 _allowInteraction: function( event ) {
12787 if ( $( event.target ).closest(".ui-dialog").length ) {
12788 return true;
12789 }
12790
12791 // TODO: Remove hack when datepicker implements
12792 // the .ui-front logic (#8989)
12793 return !!$( event.target ).closest(".ui-datepicker").length;
12794 },
12795
12796 _createOverlay: function() {
12797 if ( !this.options.modal ) {
12798 return;
12799 }
12800
12801 var that = this,
12802 widgetFullName = this.widgetFullName;
12803 if ( !$.ui.dialog.overlayInstances ) {
12804 // Prevent use of anchors and inputs.
12805 // We use a delay in case the overlay is created from an
12806 // event that we're going to be cancelling. (#2804)
12807 this._delay(function() {
12808 // Handle .dialog().dialog("close") (#4065)
12809 if ( $.ui.dialog.overlayInstances ) {
12810 this.document.bind( "focusin.dialog", function( event ) {
12811 if ( !that._allowInteraction( event ) ) {
12812 event.preventDefault();
12813 $(".ui-dialog:visible:last .ui-dialog-content")
12814 .data( widgetFullName )._focusTabbable();
12815 }
12816 });
12817 }
12818 });
12819 }
12820
12821 this.overlay = $("<div>")
12822 .addClass("ui-widget-overlay ui-front")
12823 .appendTo( this._appendTo() );
12824 this._on( this.overlay, {
12825 mousedown: "_keepFocus"
12826 });
12827 $.ui.dialog.overlayInstances++;
12828 },
12829
12830 _destroyOverlay: function() {
12831 if ( !this.options.modal ) {
12832 return;
12833 }
12834
12835 if ( this.overlay ) {
12836 $.ui.dialog.overlayInstances--;
12837
12838 if ( !$.ui.dialog.overlayInstances ) {
12839 this.document.unbind( "focusin.dialog" );
12840 }
12841 this.overlay.remove();
12842 this.overlay = null;
12843 }
12844 }
12845 });
12846
12847 $.ui.dialog.overlayInstances = 0;
12848
12849 // DEPRECATED
12850 if ( $.uiBackCompat !== false ) {
12851 // position option with array notation
12852 // just override with old implementation
12853 $.widget( "ui.dialog", $.ui.dialog, {
12854 _position: function() {
12855 var position = this.options.position,
12856 myAt = [],
12857 offset = [ 0, 0 ],
12858 isVisible;
12859
12860 if ( position ) {
12861 if ( typeof position === "string" || (typeof position === "object" && "0" in position ) ) {
12862 myAt = position.split ? position.split(" ") : [ position[0], position[1] ];
12863 if ( myAt.length === 1 ) {
12864 myAt[1] = myAt[0];
12865 }
12866
12867 $.each( [ "left", "top" ], function( i, offsetPosition ) {
12868 if ( +myAt[ i ] === myAt[ i ] ) {
12869 offset[ i ] = myAt[ i ];
12870 myAt[ i ] = offsetPosition;
12871 }
12872 });
12873
12874 position = {
12875 my: myAt[0] + (offset[0] < 0 ? offset[0] : "+" + offset[0]) + " " +
12876 myAt[1] + (offset[1] < 0 ? offset[1] : "+" + offset[1]),
12877 at: myAt.join(" ")
12878 };
12879 }
12880
12881 position = $.extend( {}, $.ui.dialog.prototype.options.position, position );
12882 } else {
12883 position = $.ui.dialog.prototype.options.position;
12884 }
12885
12886 // need to show the dialog to get the actual offset in the position plugin
12887 isVisible = this.uiDialog.is(":visible");
12888 if ( !isVisible ) {
12889 this.uiDialog.show();
12890 }
12891 this.uiDialog.position( position );
12892 if ( !isVisible ) {
12893 this.uiDialog.hide();
12894 }
12895 }
12896 });
12897 }
12898
12899 }( jQuery ) );
12900 (function( $, undefined ) {
12901
12902 $.widget( "ui.menu", {
12903 version: "1.10.3",
12904 defaultElement: "<ul>",
12905 delay: 300,
12906 options: {
12907 icons: {
12908 submenu: "ui-icon-carat-1-e"
12909 },
12910 menus: "ul",
12911 position: {
12912 my: "left top",
12913 at: "right top"
12914 },
12915 role: "menu",
12916
12917 // callbacks
12918 blur: null,
12919 focus: null,
12920 select: null
12921 },
12922
12923 _create: function() {
12924 this.activeMenu = this.element;
12925 // flag used to prevent firing of the click handler
12926 // as the event bubbles up through nested menus
12927 this.mouseHandled = false;
12928 this.element
12929 .uniqueId()
12930 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
12931 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
12932 .attr({
12933 role: this.options.role,
12934 tabIndex: 0
12935 })
12936 // need to catch all clicks on disabled menu
12937 // not possible through _on
12938 .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
12939 if ( this.options.disabled ) {
12940 event.preventDefault();
12941 }
12942 }, this ));
12943
12944 if ( this.options.disabled ) {
12945 this.element
12946 .addClass( "ui-state-disabled" )
12947 .attr( "aria-disabled", "true" );
12948 }
12949
12950 this._on({
12951 // Prevent focus from sticking to links inside menu after clicking
12952 // them (focus should always stay on UL during navigation).
12953 "mousedown .ui-menu-item > a": function( event ) {
12954 event.preventDefault();
12955 },
12956 "click .ui-state-disabled > a": function( event ) {
12957 event.preventDefault();
12958 },
12959 "click .ui-menu-item:has(a)": function( event ) {
12960 var target = $( event.target ).closest( ".ui-menu-item" );
12961 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
12962 this.mouseHandled = true;
12963
12964 this.select( event );
12965 // Open submenu on click
12966 if ( target.has( ".ui-menu" ).length ) {
12967 this.expand( event );
12968 } else if ( !this.element.is( ":focus" ) ) {
12969 // Redirect focus to the menu
12970 this.element.trigger( "focus", [ true ] );
12971
12972 // If the active item is on the top level, let it stay active.
12973 // Otherwise, blur the active item since it is no longer visible.
12974 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
12975 clearTimeout( this.timer );
12976 }
12977 }
12978 }
12979 },
12980 "mouseenter .ui-menu-item": function( event ) {
12981 var target = $( event.currentTarget );
12982 // Remove ui-state-active class from siblings of the newly focused menu item
12983 // to avoid a jump caused by adjacent elements both having a class with a border
12984 target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
12985 this.focus( event, target );
12986 },
12987 mouseleave: "collapseAll",
12988 "mouseleave .ui-menu": "collapseAll",
12989 focus: function( event, keepActiveItem ) {
12990 // If there's already an active item, keep it active
12991 // If not, activate the first item
12992 var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
12993
12994 if ( !keepActiveItem ) {
12995 this.focus( event, item );
12996 }
12997 },
12998 blur: function( event ) {
12999 this._delay(function() {
13000 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
13001 this.collapseAll( event );
13002 }
13003 });
13004 },
13005 keydown: "_keydown"
13006 });
13007
13008 this.refresh();
13009
13010 // Clicks outside of a menu collapse any open menus
13011 this._on( this.document, {
13012 click: function( event ) {
13013 if ( !$( event.target ).closest( ".ui-menu" ).length ) {
13014 this.collapseAll( event );
13015 }
13016
13017 // Reset the mouseHandled flag
13018 this.mouseHandled = false;
13019 }
13020 });
13021 },
13022
13023 _destroy: function() {
13024 // Destroy (sub)menus
13025 this.element
13026 .removeAttr( "aria-activedescendant" )
13027 .find( ".ui-menu" ).addBack()
13028 .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
13029 .removeAttr( "role" )
13030 .removeAttr( "tabIndex" )
13031 .removeAttr( "aria-labelledby" )
13032 .removeAttr( "aria-expanded" )
13033 .removeAttr( "aria-hidden" )
13034 .removeAttr( "aria-disabled" )
13035 .removeUniqueId()
13036 .show();
13037
13038 // Destroy menu items
13039 this.element.find( ".ui-menu-item" )
13040 .removeClass( "ui-menu-item" )
13041 .removeAttr( "role" )
13042 .removeAttr( "aria-disabled" )
13043 .children( "a" )
13044 .removeUniqueId()
13045 .removeClass( "ui-corner-all ui-state-hover" )
13046 .removeAttr( "tabIndex" )
13047 .removeAttr( "role" )
13048 .removeAttr( "aria-haspopup" )
13049 .children().each( function() {
13050 var elem = $( this );
13051 if ( elem.data( "ui-menu-submenu-carat" ) ) {
13052 elem.remove();
13053 }
13054 });
13055
13056 // Destroy menu dividers
13057 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
13058 },
13059
13060 _keydown: function( event ) {
13061 /*jshint maxcomplexity:20*/
13062 var match, prev, character, skip, regex,
13063 preventDefault = true;
13064
13065 function escape( value ) {
13066 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
13067 }
13068
13069 switch ( event.keyCode ) {
13070 case $.ui.keyCode.PAGE_UP:
13071 this.previousPage( event );
13072 break;
13073 case $.ui.keyCode.PAGE_DOWN:
13074 this.nextPage( event );
13075 break;
13076 case $.ui.keyCode.HOME:
13077 this._move( "first", "first", event );
13078 break;
13079 case $.ui.keyCode.END:
13080 this._move( "last", "last", event );
13081 break;
13082 case $.ui.keyCode.UP:
13083 this.previous( event );
13084 break;
13085 case $.ui.keyCode.DOWN:
13086 this.next( event );
13087 break;
13088 case $.ui.keyCode.LEFT:
13089 this.collapse( event );
13090 break;
13091 case $.ui.keyCode.RIGHT:
13092 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
13093 this.expand( event );
13094 }
13095 break;
13096 case $.ui.keyCode.ENTER:
13097 case $.ui.keyCode.SPACE:
13098 this._activate( event );
13099 break;
13100 case $.ui.keyCode.ESCAPE:
13101 this.collapse( event );
13102 break;
13103 default:
13104 preventDefault = false;
13105 prev = this.previousFilter || "";
13106 character = String.fromCharCode( event.keyCode );
13107 skip = false;
13108
13109 clearTimeout( this.filterTimer );
13110
13111 if ( character === prev ) {
13112 skip = true;
13113 } else {
13114 character = prev + character;
13115 }
13116
13117 regex = new RegExp( "^" + escape( character ), "i" );
13118 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
13119 return regex.test( $( this ).children( "a" ).text() );
13120 });
13121 match = skip && match.index( this.active.next() ) !== -1 ?
13122 this.active.nextAll( ".ui-menu-item" ) :
13123 match;
13124
13125 // If no matches on the current filter, reset to the last character pressed
13126 // to move down the menu to the first item that starts with that character
13127 if ( !match.length ) {
13128 character = String.fromCharCode( event.keyCode );
13129 regex = new RegExp( "^" + escape( character ), "i" );
13130 match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
13131 return regex.test( $( this ).children( "a" ).text() );
13132 });
13133 }
13134
13135 if ( match.length ) {
13136 this.focus( event, match );
13137 if ( match.length > 1 ) {
13138 this.previousFilter = character;
13139 this.filterTimer = this._delay(function() {
13140 delete this.previousFilter;
13141 }, 1000 );
13142 } else {
13143 delete this.previousFilter;
13144 }
13145 } else {
13146 delete this.previousFilter;
13147 }
13148 }
13149
13150 if ( preventDefault ) {
13151 event.preventDefault();
13152 }
13153 },
13154
13155 _activate: function( event ) {
13156 if ( !this.active.is( ".ui-state-disabled" ) ) {
13157 if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
13158 this.expand( event );
13159 } else {
13160 this.select( event );
13161 }
13162 }
13163 },
13164
13165 refresh: function() {
13166 var menus,
13167 icon = this.options.icons.submenu,
13168 submenus = this.element.find( this.options.menus );
13169
13170 // Initialize nested menus
13171 submenus.filter( ":not(.ui-menu)" )
13172 .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
13173 .hide()
13174 .attr({
13175 role: this.options.role,
13176 "aria-hidden": "true",
13177 "aria-expanded": "false"
13178 })
13179 .each(function() {
13180 var menu = $( this ),
13181 item = menu.prev( "a" ),
13182 submenuCarat = $( "<span>" )
13183 .addClass( "ui-menu-icon ui-icon " + icon )
13184 .data( "ui-menu-submenu-carat", true );
13185
13186 item
13187 .attr( "aria-haspopup", "true" )
13188 .prepend( submenuCarat );
13189 menu.attr( "aria-labelledby", item.attr( "id" ) );
13190 });
13191
13192 menus = submenus.add( this.element );
13193
13194 // Don't refresh list items that are already adapted
13195 menus.children( ":not(.ui-menu-item):has(a)" )
13196 .addClass( "ui-menu-item" )
13197 .attr( "role", "presentation" )
13198 .children( "a" )
13199 .uniqueId()
13200 .addClass( "ui-corner-all" )
13201 .attr({
13202 tabIndex: -1,
13203 role: this._itemRole()
13204 });
13205
13206 // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
13207 menus.children( ":not(.ui-menu-item)" ).each(function() {
13208 var item = $( this );
13209 // hyphen, em dash, en dash
13210 if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
13211 item.addClass( "ui-widget-content ui-menu-divider" );
13212 }
13213 });
13214
13215 // Add aria-disabled attribute to any disabled menu item
13216 menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
13217
13218 // If the active item has been removed, blur the menu
13219 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
13220 this.blur();
13221 }
13222 },
13223
13224 _itemRole: function() {
13225 return {
13226 menu: "menuitem",
13227 listbox: "option"
13228 }[ this.options.role ];
13229 },
13230
13231 _setOption: function( key, value ) {
13232 if ( key === "icons" ) {
13233 this.element.find( ".ui-menu-icon" )
13234 .removeClass( this.options.icons.submenu )
13235 .addClass( value.submenu );
13236 }
13237 this._super( key, value );
13238 },
13239
13240 focus: function( event, item ) {
13241 var nested, focused;
13242 this.blur( event, event && event.type === "focus" );
13243
13244 this._scrollIntoView( item );
13245
13246 this.active = item.first();
13247 focused = this.active.children( "a" ).addClass( "ui-state-focus" );
13248 // Only update aria-activedescendant if there's a role
13249 // otherwise we assume focus is managed elsewhere
13250 if ( this.options.role ) {
13251 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
13252 }
13253
13254 // Highlight active parent menu item, if any
13255 this.active
13256 .parent()
13257 .closest( ".ui-menu-item" )
13258 .children( "a:first" )
13259 .addClass( "ui-state-active" );
13260
13261 if ( event && event.type === "keydown" ) {
13262 this._close();
13263 } else {
13264 this.timer = this._delay(function() {
13265 this._close();
13266 }, this.delay );
13267 }
13268
13269 nested = item.children( ".ui-menu" );
13270 if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
13271 this._startOpening(nested);
13272 }
13273 this.activeMenu = item.parent();
13274
13275 this._trigger( "focus", event, { item: item } );
13276 },
13277
13278 _scrollIntoView: function( item ) {
13279 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
13280 if ( this._hasScroll() ) {
13281 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
13282 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
13283 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
13284 scroll = this.activeMenu.scrollTop();
13285 elementHeight = this.activeMenu.height();
13286 itemHeight = item.height();
13287
13288 if ( offset < 0 ) {
13289 this.activeMenu.scrollTop( scroll + offset );
13290 } else if ( offset + itemHeight > elementHeight ) {
13291 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
13292 }
13293 }
13294 },
13295
13296 blur: function( event, fromFocus ) {
13297 if ( !fromFocus ) {
13298 clearTimeout( this.timer );
13299 }
13300
13301 if ( !this.active ) {
13302 return;
13303 }
13304
13305 this.active.children( "a" ).removeClass( "ui-state-focus" );
13306 this.active = null;
13307
13308 this._trigger( "blur", event, { item: this.active } );
13309 },
13310
13311 _startOpening: function( submenu ) {
13312 clearTimeout( this.timer );
13313
13314 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
13315 // shift in the submenu position when mousing over the carat icon
13316 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
13317 return;
13318 }
13319
13320 this.timer = this._delay(function() {
13321 this._close();
13322 this._open( submenu );
13323 }, this.delay );
13324 },
13325
13326 _open: function( submenu ) {
13327 var position = $.extend({
13328 of: this.active
13329 }, this.options.position );
13330
13331 clearTimeout( this.timer );
13332 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
13333 .hide()
13334 .attr( "aria-hidden", "true" );
13335
13336 submenu
13337 .show()
13338 .removeAttr( "aria-hidden" )
13339 .attr( "aria-expanded", "true" )
13340 .position( position );
13341 },
13342
13343 collapseAll: function( event, all ) {
13344 clearTimeout( this.timer );
13345 this.timer = this._delay(function() {
13346 // If we were passed an event, look for the submenu that contains the event
13347 var currentMenu = all ? this.element :
13348 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
13349
13350 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
13351 if ( !currentMenu.length ) {
13352 currentMenu = this.element;
13353 }
13354
13355 this._close( currentMenu );
13356
13357 this.blur( event );
13358 this.activeMenu = currentMenu;
13359 }, this.delay );
13360 },
13361
13362 // With no arguments, closes the currently active menu - if nothing is active
13363 // it closes all menus. If passed an argument, it will search for menus BELOW
13364 _close: function( startMenu ) {
13365 if ( !startMenu ) {
13366 startMenu = this.active ? this.active.parent() : this.element;
13367 }
13368
13369 startMenu
13370 .find( ".ui-menu" )
13371 .hide()
13372 .attr( "aria-hidden", "true" )
13373 .attr( "aria-expanded", "false" )
13374 .end()
13375 .find( "a.ui-state-active" )
13376 .removeClass( "ui-state-active" );
13377 },
13378
13379 collapse: function( event ) {
13380 var newItem = this.active &&
13381 this.active.parent().closest( ".ui-menu-item", this.element );
13382 if ( newItem && newItem.length ) {
13383 this._close();
13384 this.focus( event, newItem );
13385 }
13386 },
13387
13388 expand: function( event ) {
13389 var newItem = this.active &&
13390 this.active
13391 .children( ".ui-menu " )
13392 .children( ".ui-menu-item" )
13393 .first();
13394
13395 if ( newItem && newItem.length ) {
13396 this._open( newItem.parent() );
13397
13398 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
13399 this._delay(function() {
13400 this.focus( event, newItem );
13401 });
13402 }
13403 },
13404
13405 next: function( event ) {
13406 this._move( "next", "first", event );
13407 },
13408
13409 previous: function( event ) {
13410 this._move( "prev", "last", event );
13411 },
13412
13413 isFirstItem: function() {
13414 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
13415 },
13416
13417 isLastItem: function() {
13418 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
13419 },
13420
13421 _move: function( direction, filter, event ) {
13422 var next;
13423 if ( this.active ) {
13424 if ( direction === "first" || direction === "last" ) {
13425 next = this.active
13426 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
13427 .eq( -1 );
13428 } else {
13429 next = this.active
13430 [ direction + "All" ]( ".ui-menu-item" )
13431 .eq( 0 );
13432 }
13433 }
13434 if ( !next || !next.length || !this.active ) {
13435 next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
13436 }
13437
13438 this.focus( event, next );
13439 },
13440
13441 nextPage: function( event ) {
13442 var item, base, height;
13443
13444 if ( !this.active ) {
13445 this.next( event );
13446 return;
13447 }
13448 if ( this.isLastItem() ) {
13449 return;
13450 }
13451 if ( this._hasScroll() ) {
13452 base = this.active.offset().top;
13453 height = this.element.height();
13454 this.active.nextAll( ".ui-menu-item" ).each(function() {
13455 item = $( this );
13456 return item.offset().top - base - height < 0;
13457 });
13458
13459 this.focus( event, item );
13460 } else {
13461 this.focus( event, this.activeMenu.children( ".ui-menu-item" )
13462 [ !this.active ? "first" : "last" ]() );
13463 }
13464 },
13465
13466 previousPage: function( event ) {
13467 var item, base, height;
13468 if ( !this.active ) {
13469 this.next( event );
13470 return;
13471 }
13472 if ( this.isFirstItem() ) {
13473 return;
13474 }
13475 if ( this._hasScroll() ) {
13476 base = this.active.offset().top;
13477 height = this.element.height();
13478 this.active.prevAll( ".ui-menu-item" ).each(function() {
13479 item = $( this );
13480 return item.offset().top - base + height > 0;
13481 });
13482
13483 this.focus( event, item );
13484 } else {
13485 this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
13486 }
13487 },
13488
13489 _hasScroll: function() {
13490 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
13491 },
13492
13493 select: function( event ) {
13494 // TODO: It should never be possible to not have an active item at this
13495 // point, but the tests don't trigger mouseenter before click.
13496 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
13497 var ui = { item: this.active };
13498 if ( !this.active.has( ".ui-menu" ).length ) {
13499 this.collapseAll( event, true );
13500 }
13501 this._trigger( "select", event, ui );
13502 }
13503 });
13504
13505 }( jQuery ));
13506 (function( $, undefined ) {
13507
13508 $.widget( "ui.progressbar", {
13509 version: "1.10.3",
13510 options: {
13511 max: 100,
13512 value: 0,
13513
13514 change: null,
13515 complete: null
13516 },
13517
13518 min: 0,
13519
13520 _create: function() {
13521 // Constrain initial value
13522 this.oldValue = this.options.value = this._constrainedValue();
13523
13524 this.element
13525 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
13526 .attr({
13527 // Only set static values, aria-valuenow and aria-valuemax are
13528 // set inside _refreshValue()
13529 role: "progressbar",
13530 "aria-valuemin": this.min
13531 });
13532
13533 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
13534 .appendTo( this.element );
13535
13536 this._refreshValue();
13537 },
13538
13539 _destroy: function() {
13540 this.element
13541 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
13542 .removeAttr( "role" )
13543 .removeAttr( "aria-valuemin" )
13544 .removeAttr( "aria-valuemax" )
13545 .removeAttr( "aria-valuenow" );
13546
13547 this.valueDiv.remove();
13548 },
13549
13550 value: function( newValue ) {
13551 if ( newValue === undefined ) {
13552 return this.options.value;
13553 }
13554
13555 this.options.value = this._constrainedValue( newValue );
13556 this._refreshValue();
13557 },
13558
13559 _constrainedValue: function( newValue ) {
13560 if ( newValue === undefined ) {
13561 newValue = this.options.value;
13562 }
13563
13564 this.indeterminate = newValue === false;
13565
13566 // sanitize value
13567 if ( typeof newValue !== "number" ) {
13568 newValue = 0;
13569 }
13570
13571 return this.indeterminate ? false :
13572 Math.min( this.options.max, Math.max( this.min, newValue ) );
13573 },
13574
13575 _setOptions: function( options ) {
13576 // Ensure "value" option is set after other values (like max)
13577 var value = options.value;
13578 delete options.value;
13579
13580 this._super( options );
13581
13582 this.options.value = this._constrainedValue( value );
13583 this._refreshValue();
13584 },
13585
13586 _setOption: function( key, value ) {
13587 if ( key === "max" ) {
13588 // Don't allow a max less than min
13589 value = Math.max( this.min, value );
13590 }
13591
13592 this._super( key, value );
13593 },
13594
13595 _percentage: function() {
13596 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
13597 },
13598
13599 _refreshValue: function() {
13600 var value = this.options.value,
13601 percentage = this._percentage();
13602
13603 this.valueDiv
13604 .toggle( this.indeterminate || value > this.min )
13605 .toggleClass( "ui-corner-right", value === this.options.max )
13606 .width( percentage.toFixed(0) + "%" );
13607
13608 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
13609
13610 if ( this.indeterminate ) {
13611 this.element.removeAttr( "aria-valuenow" );
13612 if ( !this.overlayDiv ) {
13613 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
13614 }
13615 } else {
13616 this.element.attr({
13617 "aria-valuemax": this.options.max,
13618 "aria-valuenow": value
13619 });
13620 if ( this.overlayDiv ) {
13621 this.overlayDiv.remove();
13622 this.overlayDiv = null;
13623 }
13624 }
13625
13626 if ( this.oldValue !== value ) {
13627 this.oldValue = value;
13628 this._trigger( "change" );
13629 }
13630 if ( value === this.options.max ) {
13631 this._trigger( "complete" );
13632 }
13633 }
13634 });
13635
13636 })( jQuery );
13637 (function( $, undefined ) {
13638
13639 // number of pages in a slider
13640 // (how many times can you page up/down to go through the whole range)
13641 var numPages = 5;
13642
13643 $.widget( "ui.slider", $.ui.mouse, {
13644 version: "1.10.3",
13645 widgetEventPrefix: "slide",
13646
13647 options: {
13648 animate: false,
13649 distance: 0,
13650 max: 100,
13651 min: 0,
13652 orientation: "horizontal",
13653 range: false,
13654 step: 1,
13655 value: 0,
13656 values: null,
13657
13658 // callbacks
13659 change: null,
13660 slide: null,
13661 start: null,
13662 stop: null
13663 },
13664
13665 _create: function() {
13666 this._keySliding = false;
13667 this._mouseSliding = false;
13668 this._animateOff = true;
13669 this._handleIndex = null;
13670 this._detectOrientation();
13671 this._mouseInit();
13672
13673 this.element
13674 .addClass( "ui-slider" +
13675 " ui-slider-" + this.orientation +
13676 " ui-widget" +
13677 " ui-widget-content" +
13678 " ui-corner-all");
13679
13680 this._refresh();
13681 this._setOption( "disabled", this.options.disabled );
13682
13683 this._animateOff = false;
13684 },
13685
13686 _refresh: function() {
13687 this._createRange();
13688 this._createHandles();
13689 this._setupEvents();
13690 this._refreshValue();
13691 },
13692
13693 _createHandles: function() {
13694 var i, handleCount,
13695 options = this.options,
13696 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
13697 handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
13698 handles = [];
13699
13700 handleCount = ( options.values && options.values.length ) || 1;
13701
13702 if ( existingHandles.length > handleCount ) {
13703 existingHandles.slice( handleCount ).remove();
13704 existingHandles = existingHandles.slice( 0, handleCount );
13705 }
13706
13707 for ( i = existingHandles.length; i < handleCount; i++ ) {
13708 handles.push( handle );
13709 }
13710
13711 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
13712
13713 this.handle = this.handles.eq( 0 );
13714
13715 this.handles.each(function( i ) {
13716 $( this ).data( "ui-slider-handle-index", i );
13717 });
13718 },
13719
13720 _createRange: function() {
13721 var options = this.options,
13722 classes = "";
13723
13724 if ( options.range ) {
13725 if ( options.range === true ) {
13726 if ( !options.values ) {
13727 options.values = [ this._valueMin(), this._valueMin() ];
13728 } else if ( options.values.length && options.values.length !== 2 ) {
13729 options.values = [ options.values[0], options.values[0] ];
13730 } else if ( $.isArray( options.values ) ) {
13731 options.values = options.values.slice(0);
13732 }
13733 }
13734
13735 if ( !this.range || !this.range.length ) {
13736 this.range = $( "<div></div>" )
13737 .appendTo( this.element );
13738
13739 classes = "ui-slider-range" +
13740 // note: this isn't the most fittingly semantic framework class for this element,
13741 // but worked best visually with a variety of themes
13742 " ui-widget-header ui-corner-all";
13743 } else {
13744 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
13745 // Handle range switching from true to min/max
13746 .css({
13747 "left": "",
13748 "bottom": ""
13749 });
13750 }
13751
13752 this.range.addClass( classes +
13753 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
13754 } else {
13755 this.range = $([]);
13756 }
13757 },
13758
13759 _setupEvents: function() {
13760 var elements = this.handles.add( this.range ).filter( "a" );
13761 this._off( elements );
13762 this._on( elements, this._handleEvents );
13763 this._hoverable( elements );
13764 this._focusable( elements );
13765 },
13766
13767 _destroy: function() {
13768 this.handles.remove();
13769 this.range.remove();
13770
13771 this.element
13772 .removeClass( "ui-slider" +
13773 " ui-slider-horizontal" +
13774 " ui-slider-vertical" +
13775 " ui-widget" +
13776 " ui-widget-content" +
13777 " ui-corner-all" );
13778
13779 this._mouseDestroy();
13780 },
13781
13782 _mouseCapture: function( event ) {
13783 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
13784 that = this,
13785 o = this.options;
13786
13787 if ( o.disabled ) {
13788 return false;
13789 }
13790
13791 this.elementSize = {
13792 width: this.element.outerWidth(),
13793 height: this.element.outerHeight()
13794 };
13795 this.elementOffset = this.element.offset();
13796
13797 position = { x: event.pageX, y: event.pageY };
13798 normValue = this._normValueFromMouse( position );
13799 distance = this._valueMax() - this._valueMin() + 1;
13800 this.handles.each(function( i ) {
13801 var thisDistance = Math.abs( normValue - that.values(i) );
13802 if (( distance > thisDistance ) ||
13803 ( distance === thisDistance &&
13804 (i === that._lastChangedValue || that.values(i) === o.min ))) {
13805 distance = thisDistance;
13806 closestHandle = $( this );
13807 index = i;
13808 }
13809 });
13810
13811 allowed = this._start( event, index );
13812 if ( allowed === false ) {
13813 return false;
13814 }
13815 this._mouseSliding = true;
13816
13817 this._handleIndex = index;
13818
13819 closestHandle
13820 .addClass( "ui-state-active" )
13821 .focus();
13822
13823 offset = closestHandle.offset();
13824 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
13825 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
13826 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
13827 top: event.pageY - offset.top -
13828 ( closestHandle.height() / 2 ) -
13829 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
13830 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
13831 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
13832 };
13833
13834 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
13835 this._slide( event, index, normValue );
13836 }
13837 this._animateOff = true;
13838 return true;
13839 },
13840
13841 _mouseStart: function() {
13842 return true;
13843 },
13844
13845 _mouseDrag: function( event ) {
13846 var position = { x: event.pageX, y: event.pageY },
13847 normValue = this._normValueFromMouse( position );
13848
13849 this._slide( event, this._handleIndex, normValue );
13850
13851 return false;
13852 },
13853
13854 _mouseStop: function( event ) {
13855 this.handles.removeClass( "ui-state-active" );
13856 this._mouseSliding = false;
13857
13858 this._stop( event, this._handleIndex );
13859 this._change( event, this._handleIndex );
13860
13861 this._handleIndex = null;
13862 this._clickOffset = null;
13863 this._animateOff = false;
13864
13865 return false;
13866 },
13867
13868 _detectOrientation: function() {
13869 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
13870 },
13871
13872 _normValueFromMouse: function( position ) {
13873 var pixelTotal,
13874 pixelMouse,
13875 percentMouse,
13876 valueTotal,
13877 valueMouse;
13878
13879 if ( this.orientation === "horizontal" ) {
13880 pixelTotal = this.elementSize.width;
13881 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
13882 } else {
13883 pixelTotal = this.elementSize.height;
13884 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
13885 }
13886
13887 percentMouse = ( pixelMouse / pixelTotal );
13888 if ( percentMouse > 1 ) {
13889 percentMouse = 1;
13890 }
13891 if ( percentMouse < 0 ) {
13892 percentMouse = 0;
13893 }
13894 if ( this.orientation === "vertical" ) {
13895 percentMouse = 1 - percentMouse;
13896 }
13897
13898 valueTotal = this._valueMax() - this._valueMin();
13899 valueMouse = this._valueMin() + percentMouse * valueTotal;
13900
13901 return this._trimAlignValue( valueMouse );
13902 },
13903
13904 _start: function( event, index ) {
13905 var uiHash = {
13906 handle: this.handles[ index ],
13907 value: this.value()
13908 };
13909 if ( this.options.values && this.options.values.length ) {
13910 uiHash.value = this.values( index );
13911 uiHash.values = this.values();
13912 }
13913 return this._trigger( "start", event, uiHash );
13914 },
13915
13916 _slide: function( event, index, newVal ) {
13917 var otherVal,
13918 newValues,
13919 allowed;
13920
13921 if ( this.options.values && this.options.values.length ) {
13922 otherVal = this.values( index ? 0 : 1 );
13923
13924 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
13925 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
13926 ) {
13927 newVal = otherVal;
13928 }
13929
13930 if ( newVal !== this.values( index ) ) {
13931 newValues = this.values();
13932 newValues[ index ] = newVal;
13933 // A slide can be canceled by returning false from the slide callback
13934 allowed = this._trigger( "slide", event, {
13935 handle: this.handles[ index ],
13936 value: newVal,
13937 values: newValues
13938 } );
13939 otherVal = this.values( index ? 0 : 1 );
13940 if ( allowed !== false ) {
13941 this.values( index, newVal, true );
13942 }
13943 }
13944 } else {
13945 if ( newVal !== this.value() ) {
13946 // A slide can be canceled by returning false from the slide callback
13947 allowed = this._trigger( "slide", event, {
13948 handle: this.handles[ index ],
13949 value: newVal
13950 } );
13951 if ( allowed !== false ) {
13952 this.value( newVal );
13953 }
13954 }
13955 }
13956 },
13957
13958 _stop: function( event, index ) {
13959 var uiHash = {
13960 handle: this.handles[ index ],
13961 value: this.value()
13962 };
13963 if ( this.options.values && this.options.values.length ) {
13964 uiHash.value = this.values( index );
13965 uiHash.values = this.values();
13966 }
13967
13968 this._trigger( "stop", event, uiHash );
13969 },
13970
13971 _change: function( event, index ) {
13972 if ( !this._keySliding && !this._mouseSliding ) {
13973 var uiHash = {
13974 handle: this.handles[ index ],
13975 value: this.value()
13976 };
13977 if ( this.options.values && this.options.values.length ) {
13978 uiHash.value = this.values( index );
13979 uiHash.values = this.values();
13980 }
13981
13982 //store the last changed value index for reference when handles overlap
13983 this._lastChangedValue = index;
13984
13985 this._trigger( "change", event, uiHash );
13986 }
13987 },
13988
13989 value: function( newValue ) {
13990 if ( arguments.length ) {
13991 this.options.value = this._trimAlignValue( newValue );
13992 this._refreshValue();
13993 this._change( null, 0 );
13994 return;
13995 }
13996
13997 return this._value();
13998 },
13999
14000 values: function( index, newValue ) {
14001 var vals,
14002 newValues,
14003 i;
14004
14005 if ( arguments.length > 1 ) {
14006 this.options.values[ index ] = this._trimAlignValue( newValue );
14007 this._refreshValue();
14008 this._change( null, index );
14009 return;
14010 }
14011
14012 if ( arguments.length ) {
14013 if ( $.isArray( arguments[ 0 ] ) ) {
14014 vals = this.options.values;
14015 newValues = arguments[ 0 ];
14016 for ( i = 0; i < vals.length; i += 1 ) {
14017 vals[ i ] = this._trimAlignValue( newValues[ i ] );
14018 this._change( null, i );
14019 }
14020 this._refreshValue();
14021 } else {
14022 if ( this.options.values && this.options.values.length ) {
14023 return this._values( index );
14024 } else {
14025 return this.value();
14026 }
14027 }
14028 } else {
14029 return this._values();
14030 }
14031 },
14032
14033 _setOption: function( key, value ) {
14034 var i,
14035 valsLength = 0;
14036
14037 if ( key === "range" && this.options.range === true ) {
14038 if ( value === "min" ) {
14039 this.options.value = this._values( 0 );
14040 this.options.values = null;
14041 } else if ( value === "max" ) {
14042 this.options.value = this._values( this.options.values.length-1 );
14043 this.options.values = null;
14044 }
14045 }
14046
14047 if ( $.isArray( this.options.values ) ) {
14048 valsLength = this.options.values.length;
14049 }
14050
14051 $.Widget.prototype._setOption.apply( this, arguments );
14052
14053 switch ( key ) {
14054 case "orientation":
14055 this._detectOrientation();
14056 this.element
14057 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
14058 .addClass( "ui-slider-" + this.orientation );
14059 this._refreshValue();
14060 break;
14061 case "value":
14062 this._animateOff = true;
14063 this._refreshValue();
14064 this._change( null, 0 );
14065 this._animateOff = false;
14066 break;
14067 case "values":
14068 this._animateOff = true;
14069 this._refreshValue();
14070 for ( i = 0; i < valsLength; i += 1 ) {
14071 this._change( null, i );
14072 }
14073 this._animateOff = false;
14074 break;
14075 case "min":
14076 case "max":
14077 this._animateOff = true;
14078 this._refreshValue();
14079 this._animateOff = false;
14080 break;
14081 case "range":
14082 this._animateOff = true;
14083 this._refresh();
14084 this._animateOff = false;
14085 break;
14086 }
14087 },
14088
14089 //internal value getter
14090 // _value() returns value trimmed by min and max, aligned by step
14091 _value: function() {
14092 var val = this.options.value;
14093 val = this._trimAlignValue( val );
14094
14095 return val;
14096 },
14097
14098 //internal values getter
14099 // _values() returns array of values trimmed by min and max, aligned by step
14100 // _values( index ) returns single value trimmed by min and max, aligned by step
14101 _values: function( index ) {
14102 var val,
14103 vals,
14104 i;
14105
14106 if ( arguments.length ) {
14107 val = this.options.values[ index ];
14108 val = this._trimAlignValue( val );
14109
14110 return val;
14111 } else if ( this.options.values && this.options.values.length ) {
14112 // .slice() creates a copy of the array
14113 // this copy gets trimmed by min and max and then returned
14114 vals = this.options.values.slice();
14115 for ( i = 0; i < vals.length; i+= 1) {
14116 vals[ i ] = this._trimAlignValue( vals[ i ] );
14117 }
14118
14119 return vals;
14120 } else {
14121 return [];
14122 }
14123 },
14124
14125 // returns the step-aligned value that val is closest to, between (inclusive) min and max
14126 _trimAlignValue: function( val ) {
14127 if ( val <= this._valueMin() ) {
14128 return this._valueMin();
14129 }
14130 if ( val >= this._valueMax() ) {
14131 return this._valueMax();
14132 }
14133 var step = ( this.options.step > 0 ) ? this.options.step : 1,
14134 valModStep = (val - this._valueMin()) % step,
14135 alignValue = val - valModStep;
14136
14137 if ( Math.abs(valModStep) * 2 >= step ) {
14138 alignValue += ( valModStep > 0 ) ? step : ( -step );
14139 }
14140
14141 // Since JavaScript has problems with large floats, round
14142 // the final value to 5 digits after the decimal point (see #4124)
14143 return parseFloat( alignValue.toFixed(5) );
14144 },
14145
14146 _valueMin: function() {
14147 return this.options.min;
14148 },
14149
14150 _valueMax: function() {
14151 return this.options.max;
14152 },
14153
14154 _refreshValue: function() {
14155 var lastValPercent, valPercent, value, valueMin, valueMax,
14156 oRange = this.options.range,
14157 o = this.options,
14158 that = this,
14159 animate = ( !this._animateOff ) ? o.animate : false,
14160 _set = {};
14161
14162 if ( this.options.values && this.options.values.length ) {
14163 this.handles.each(function( i ) {
14164 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
14165 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
14166 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
14167 if ( that.options.range === true ) {
14168 if ( that.orientation === "horizontal" ) {
14169 if ( i === 0 ) {
14170 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
14171 }
14172 if ( i === 1 ) {
14173 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
14174 }
14175 } else {
14176 if ( i === 0 ) {
14177 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
14178 }
14179 if ( i === 1 ) {
14180 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
14181 }
14182 }
14183 }
14184 lastValPercent = valPercent;
14185 });
14186 } else {
14187 value = this.value();
14188 valueMin = this._valueMin();
14189 valueMax = this._valueMax();
14190 valPercent = ( valueMax !== valueMin ) ?
14191 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
14192 0;
14193 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
14194 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
14195
14196 if ( oRange === "min" && this.orientation === "horizontal" ) {
14197 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
14198 }
14199 if ( oRange === "max" && this.orientation === "horizontal" ) {
14200 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
14201 }
14202 if ( oRange === "min" && this.orientation === "vertical" ) {
14203 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
14204 }
14205 if ( oRange === "max" && this.orientation === "vertical" ) {
14206 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
14207 }
14208 }
14209 },
14210
14211 _handleEvents: {
14212 keydown: function( event ) {
14213 /*jshint maxcomplexity:25*/
14214 var allowed, curVal, newVal, step,
14215 index = $( event.target ).data( "ui-slider-handle-index" );
14216
14217 switch ( event.keyCode ) {
14218 case $.ui.keyCode.HOME:
14219 case $.ui.keyCode.END:
14220 case $.ui.keyCode.PAGE_UP:
14221 case $.ui.keyCode.PAGE_DOWN:
14222 case $.ui.keyCode.UP:
14223 case $.ui.keyCode.RIGHT:
14224 case $.ui.keyCode.DOWN:
14225 case $.ui.keyCode.LEFT:
14226 event.preventDefault();
14227 if ( !this._keySliding ) {
14228 this._keySliding = true;
14229 $( event.target ).addClass( "ui-state-active" );
14230 allowed = this._start( event, index );
14231 if ( allowed === false ) {
14232 return;
14233 }
14234 }
14235 break;
14236 }
14237
14238 step = this.options.step;
14239 if ( this.options.values && this.options.values.length ) {
14240 curVal = newVal = this.values( index );
14241 } else {
14242 curVal = newVal = this.value();
14243 }
14244
14245 switch ( event.keyCode ) {
14246 case $.ui.keyCode.HOME:
14247 newVal = this._valueMin();
14248 break;
14249 case $.ui.keyCode.END:
14250 newVal = this._valueMax();
14251 break;
14252 case $.ui.keyCode.PAGE_UP:
14253 newVal = this._trimAlignValue( curVal + ( (this._valueMax() - this._valueMin()) / numPages ) );
14254 break;
14255 case $.ui.keyCode.PAGE_DOWN:
14256 newVal = this._trimAlignValue( curVal - ( (this._valueMax() - this._valueMin()) / numPages ) );
14257 break;
14258 case $.ui.keyCode.UP:
14259 case $.ui.keyCode.RIGHT:
14260 if ( curVal === this._valueMax() ) {
14261 return;
14262 }
14263 newVal = this._trimAlignValue( curVal + step );
14264 break;
14265 case $.ui.keyCode.DOWN:
14266 case $.ui.keyCode.LEFT:
14267 if ( curVal === this._valueMin() ) {
14268 return;
14269 }
14270 newVal = this._trimAlignValue( curVal - step );
14271 break;
14272 }
14273
14274 this._slide( event, index, newVal );
14275 },
14276 click: function( event ) {
14277 event.preventDefault();
14278 },
14279 keyup: function( event ) {
14280 var index = $( event.target ).data( "ui-slider-handle-index" );
14281
14282 if ( this._keySliding ) {
14283 this._keySliding = false;
14284 this._stop( event, index );
14285 this._change( event, index );
14286 $( event.target ).removeClass( "ui-state-active" );
14287 }
14288 }
14289 }
14290
14291 });
14292
14293 }(jQuery));
14294 (function( $ ) {
14295
14296 function modifier( fn ) {
14297 return function() {
14298 var previous = this.element.val();
14299 fn.apply( this, arguments );
14300 this._refresh();
14301 if ( previous !== this.element.val() ) {
14302 this._trigger( "change" );
14303 }
14304 };
14305 }
14306
14307 $.widget( "ui.spinner", {
14308 version: "1.10.3",
14309 defaultElement: "<input>",
14310 widgetEventPrefix: "spin",
14311 options: {
14312 culture: null,
14313 icons: {
14314 down: "ui-icon-triangle-1-s",
14315 up: "ui-icon-triangle-1-n"
14316 },
14317 incremental: true,
14318 max: null,
14319 min: null,
14320 numberFormat: null,
14321 page: 10,
14322 step: 1,
14323
14324 change: null,
14325 spin: null,
14326 start: null,
14327 stop: null
14328 },
14329
14330 _create: function() {
14331 // handle string values that need to be parsed
14332 this._setOption( "max", this.options.max );
14333 this._setOption( "min", this.options.min );
14334 this._setOption( "step", this.options.step );
14335
14336 // format the value, but don't constrain
14337 this._value( this.element.val(), true );
14338
14339 this._draw();
14340 this._on( this._events );
14341 this._refresh();
14342
14343 // turning off autocomplete prevents the browser from remembering the
14344 // value when navigating through history, so we re-enable autocomplete
14345 // if the page is unloaded before the widget is destroyed. #7790
14346 this._on( this.window, {
14347 beforeunload: function() {
14348 this.element.removeAttr( "autocomplete" );
14349 }
14350 });
14351 },
14352
14353 _getCreateOptions: function() {
14354 var options = {},
14355 element = this.element;
14356
14357 $.each( [ "min", "max", "step" ], function( i, option ) {
14358 var value = element.attr( option );
14359 if ( value !== undefined && value.length ) {
14360 options[ option ] = value;
14361 }
14362 });
14363
14364 return options;
14365 },
14366
14367 _events: {
14368 keydown: function( event ) {
14369 if ( this._start( event ) && this._keydown( event ) ) {
14370 event.preventDefault();
14371 }
14372 },
14373 keyup: "_stop",
14374 focus: function() {
14375 this.previous = this.element.val();
14376 },
14377 blur: function( event ) {
14378 if ( this.cancelBlur ) {
14379 delete this.cancelBlur;
14380 return;
14381 }
14382
14383 this._stop();
14384 this._refresh();
14385 if ( this.previous !== this.element.val() ) {
14386 this._trigger( "change", event );
14387 }
14388 },
14389 mousewheel: function( event, delta ) {
14390 if ( !delta ) {
14391 return;
14392 }
14393 if ( !this.spinning && !this._start( event ) ) {
14394 return false;
14395 }
14396
14397 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
14398 clearTimeout( this.mousewheelTimer );
14399 this.mousewheelTimer = this._delay(function() {
14400 if ( this.spinning ) {
14401 this._stop( event );
14402 }
14403 }, 100 );
14404 event.preventDefault();
14405 },
14406 "mousedown .ui-spinner-button": function( event ) {
14407 var previous;
14408
14409 // We never want the buttons to have focus; whenever the user is
14410 // interacting with the spinner, the focus should be on the input.
14411 // If the input is focused then this.previous is properly set from
14412 // when the input first received focus. If the input is not focused
14413 // then we need to set this.previous based on the value before spinning.
14414 previous = this.element[0] === this.document[0].activeElement ?
14415 this.previous : this.element.val();
14416 function checkFocus() {
14417 var isActive = this.element[0] === this.document[0].activeElement;
14418 if ( !isActive ) {
14419 this.element.focus();
14420 this.previous = previous;
14421 // support: IE
14422 // IE sets focus asynchronously, so we need to check if focus
14423 // moved off of the input because the user clicked on the button.
14424 this._delay(function() {
14425 this.previous = previous;
14426 });
14427 }
14428 }
14429
14430 // ensure focus is on (or stays on) the text field
14431 event.preventDefault();
14432 checkFocus.call( this );
14433
14434 // support: IE
14435 // IE doesn't prevent moving focus even with event.preventDefault()
14436 // so we set a flag to know when we should ignore the blur event
14437 // and check (again) if focus moved off of the input.
14438 this.cancelBlur = true;
14439 this._delay(function() {
14440 delete this.cancelBlur;
14441 checkFocus.call( this );
14442 });
14443
14444 if ( this._start( event ) === false ) {
14445 return;
14446 }
14447
14448 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14449 },
14450 "mouseup .ui-spinner-button": "_stop",
14451 "mouseenter .ui-spinner-button": function( event ) {
14452 // button will add ui-state-active if mouse was down while mouseleave and kept down
14453 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
14454 return;
14455 }
14456
14457 if ( this._start( event ) === false ) {
14458 return false;
14459 }
14460 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
14461 },
14462 // TODO: do we really want to consider this a stop?
14463 // shouldn't we just stop the repeater and wait until mouseup before
14464 // we trigger the stop event?
14465 "mouseleave .ui-spinner-button": "_stop"
14466 },
14467
14468 _draw: function() {
14469 var uiSpinner = this.uiSpinner = this.element
14470 .addClass( "ui-spinner-input" )
14471 .attr( "autocomplete", "off" )
14472 .wrap( this._uiSpinnerHtml() )
14473 .parent()
14474 // add buttons
14475 .append( this._buttonHtml() );
14476
14477 this.element.attr( "role", "spinbutton" );
14478
14479 // button bindings
14480 this.buttons = uiSpinner.find( ".ui-spinner-button" )
14481 .attr( "tabIndex", -1 )
14482 .button()
14483 .removeClass( "ui-corner-all" );
14484
14485 // IE 6 doesn't understand height: 50% for the buttons
14486 // unless the wrapper has an explicit height
14487 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
14488 uiSpinner.height() > 0 ) {
14489 uiSpinner.height( uiSpinner.height() );
14490 }
14491
14492 // disable spinner if element was already disabled
14493 if ( this.options.disabled ) {
14494 this.disable();
14495 }
14496 },
14497
14498 _keydown: function( event ) {
14499 var options = this.options,
14500 keyCode = $.ui.keyCode;
14501
14502 switch ( event.keyCode ) {
14503 case keyCode.UP:
14504 this._repeat( null, 1, event );
14505 return true;
14506 case keyCode.DOWN:
14507 this._repeat( null, -1, event );
14508 return true;
14509 case keyCode.PAGE_UP:
14510 this._repeat( null, options.page, event );
14511 return true;
14512 case keyCode.PAGE_DOWN:
14513 this._repeat( null, -options.page, event );
14514 return true;
14515 }
14516
14517 return false;
14518 },
14519
14520 _uiSpinnerHtml: function() {
14521 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
14522 },
14523
14524 _buttonHtml: function() {
14525 return "" +
14526 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
14527 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
14528 "</a>" +
14529 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
14530 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
14531 "</a>";
14532 },
14533
14534 _start: function( event ) {
14535 if ( !this.spinning && this._trigger( "start", event ) === false ) {
14536 return false;
14537 }
14538
14539 if ( !this.counter ) {
14540 this.counter = 1;
14541 }
14542 this.spinning = true;
14543 return true;
14544 },
14545
14546 _repeat: function( i, steps, event ) {
14547 i = i || 500;
14548
14549 clearTimeout( this.timer );
14550 this.timer = this._delay(function() {
14551 this._repeat( 40, steps, event );
14552 }, i );
14553
14554 this._spin( steps * this.options.step, event );
14555 },
14556
14557 _spin: function( step, event ) {
14558 var value = this.value() || 0;
14559
14560 if ( !this.counter ) {
14561 this.counter = 1;
14562 }
14563
14564 value = this._adjustValue( value + step * this._increment( this.counter ) );
14565
14566 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
14567 this._value( value );
14568 this.counter++;
14569 }
14570 },
14571
14572 _increment: function( i ) {
14573 var incremental = this.options.incremental;
14574
14575 if ( incremental ) {
14576 return $.isFunction( incremental ) ?
14577 incremental( i ) :
14578 Math.floor( i*i*i/50000 - i*i/500 + 17*i/200 + 1 );
14579 }
14580
14581 return 1;
14582 },
14583
14584 _precision: function() {
14585 var precision = this._precisionOf( this.options.step );
14586 if ( this.options.min !== null ) {
14587 precision = Math.max( precision, this._precisionOf( this.options.min ) );
14588 }
14589 return precision;
14590 },
14591
14592 _precisionOf: function( num ) {
14593 var str = num.toString(),
14594 decimal = str.indexOf( "." );
14595 return decimal === -1 ? 0 : str.length - decimal - 1;
14596 },
14597
14598 _adjustValue: function( value ) {
14599 var base, aboveMin,
14600 options = this.options;
14601
14602 // make sure we're at a valid step
14603 // - find out where we are relative to the base (min or 0)
14604 base = options.min !== null ? options.min : 0;
14605 aboveMin = value - base;
14606 // - round to the nearest step
14607 aboveMin = Math.round(aboveMin / options.step) * options.step;
14608 // - rounding is based on 0, so adjust back to our base
14609 value = base + aboveMin;
14610
14611 // fix precision from bad JS floating point math
14612 value = parseFloat( value.toFixed( this._precision() ) );
14613
14614 // clamp the value
14615 if ( options.max !== null && value > options.max) {
14616 return options.max;
14617 }
14618 if ( options.min !== null && value < options.min ) {
14619 return options.min;
14620 }
14621
14622 return value;
14623 },
14624
14625 _stop: function( event ) {
14626 if ( !this.spinning ) {
14627 return;
14628 }
14629
14630 clearTimeout( this.timer );
14631 clearTimeout( this.mousewheelTimer );
14632 this.counter = 0;
14633 this.spinning = false;
14634 this._trigger( "stop", event );
14635 },
14636
14637 _setOption: function( key, value ) {
14638 if ( key === "culture" || key === "numberFormat" ) {
14639 var prevValue = this._parse( this.element.val() );
14640 this.options[ key ] = value;
14641 this.element.val( this._format( prevValue ) );
14642 return;
14643 }
14644
14645 if ( key === "max" || key === "min" || key === "step" ) {
14646 if ( typeof value === "string" ) {
14647 value = this._parse( value );
14648 }
14649 }
14650 if ( key === "icons" ) {
14651 this.buttons.first().find( ".ui-icon" )
14652 .removeClass( this.options.icons.up )
14653 .addClass( value.up );
14654 this.buttons.last().find( ".ui-icon" )
14655 .removeClass( this.options.icons.down )
14656 .addClass( value.down );
14657 }
14658
14659 this._super( key, value );
14660
14661 if ( key === "disabled" ) {
14662 if ( value ) {
14663 this.element.prop( "disabled", true );
14664 this.buttons.button( "disable" );
14665 } else {
14666 this.element.prop( "disabled", false );
14667 this.buttons.button( "enable" );
14668 }
14669 }
14670 },
14671
14672 _setOptions: modifier(function( options ) {
14673 this._super( options );
14674 this._value( this.element.val() );
14675 }),
14676
14677 _parse: function( val ) {
14678 if ( typeof val === "string" && val !== "" ) {
14679 val = window.Globalize && this.options.numberFormat ?
14680 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
14681 }
14682 return val === "" || isNaN( val ) ? null : val;
14683 },
14684
14685 _format: function( value ) {
14686 if ( value === "" ) {
14687 return "";
14688 }
14689 return window.Globalize && this.options.numberFormat ?
14690 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
14691 value;
14692 },
14693
14694 _refresh: function() {
14695 this.element.attr({
14696 "aria-valuemin": this.options.min,
14697 "aria-valuemax": this.options.max,
14698 // TODO: what should we do with values that can't be parsed?
14699 "aria-valuenow": this._parse( this.element.val() )
14700 });
14701 },
14702
14703 // update the value without triggering change
14704 _value: function( value, allowAny ) {
14705 var parsed;
14706 if ( value !== "" ) {
14707 parsed = this._parse( value );
14708 if ( parsed !== null ) {
14709 if ( !allowAny ) {
14710 parsed = this._adjustValue( parsed );
14711 }
14712 value = this._format( parsed );
14713 }
14714 }
14715 this.element.val( value );
14716 this._refresh();
14717 },
14718
14719 _destroy: function() {
14720 this.element
14721 .removeClass( "ui-spinner-input" )
14722 .prop( "disabled", false )
14723 .removeAttr( "autocomplete" )
14724 .removeAttr( "role" )
14725 .removeAttr( "aria-valuemin" )
14726 .removeAttr( "aria-valuemax" )
14727 .removeAttr( "aria-valuenow" );
14728 this.uiSpinner.replaceWith( this.element );
14729 },
14730
14731 stepUp: modifier(function( steps ) {
14732 this._stepUp( steps );
14733 }),
14734 _stepUp: function( steps ) {
14735 if ( this._start() ) {
14736 this._spin( (steps || 1) * this.options.step );
14737 this._stop();
14738 }
14739 },
14740
14741 stepDown: modifier(function( steps ) {
14742 this._stepDown( steps );
14743 }),
14744 _stepDown: function( steps ) {
14745 if ( this._start() ) {
14746 this._spin( (steps || 1) * -this.options.step );
14747 this._stop();
14748 }
14749 },
14750
14751 pageUp: modifier(function( pages ) {
14752 this._stepUp( (pages || 1) * this.options.page );
14753 }),
14754
14755 pageDown: modifier(function( pages ) {
14756 this._stepDown( (pages || 1) * this.options.page );
14757 }),
14758
14759 value: function( newVal ) {
14760 if ( !arguments.length ) {
14761 return this._parse( this.element.val() );
14762 }
14763 modifier( this._value ).call( this, newVal );
14764 },
14765
14766 widget: function() {
14767 return this.uiSpinner;
14768 }
14769 });
14770
14771 }( jQuery ) );
14772 (function( $, undefined ) {
14773
14774 var tabId = 0,
14775 rhash = /#.*$/;
14776
14777 function getNextTabId() {
14778 return ++tabId;
14779 }
14780
14781 function isLocal( anchor ) {
14782 return anchor.hash.length > 1 &&
14783 decodeURIComponent( anchor.href.replace( rhash, "" ) ) ===
14784 decodeURIComponent( location.href.replace( rhash, "" ) );
14785 }
14786
14787 $.widget( "ui.tabs", {
14788 version: "1.10.3",
14789 delay: 300,
14790 options: {
14791 active: null,
14792 collapsible: false,
14793 event: "click",
14794 heightStyle: "content",
14795 hide: null,
14796 show: null,
14797
14798 // callbacks
14799 activate: null,
14800 beforeActivate: null,
14801 beforeLoad: null,
14802 load: null
14803 },
14804
14805 _create: function() {
14806 var that = this,
14807 options = this.options;
14808
14809 this.running = false;
14810
14811 this.element
14812 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
14813 .toggleClass( "ui-tabs-collapsible", options.collapsible )
14814 // Prevent users from focusing disabled tabs via click
14815 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
14816 if ( $( this ).is( ".ui-state-disabled" ) ) {
14817 event.preventDefault();
14818 }
14819 })
14820 // support: IE <9
14821 // Preventing the default action in mousedown doesn't prevent IE
14822 // from focusing the element, so if the anchor gets focused, blur.
14823 // We don't have to worry about focusing the previously focused
14824 // element since clicking on a non-focusable element should focus
14825 // the body anyway.
14826 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
14827 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
14828 this.blur();
14829 }
14830 });
14831
14832 this._processTabs();
14833 options.active = this._initialActive();
14834
14835 // Take disabling tabs via class attribute from HTML
14836 // into account and update option properly.
14837 if ( $.isArray( options.disabled ) ) {
14838 options.disabled = $.unique( options.disabled.concat(
14839 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
14840 return that.tabs.index( li );
14841 })
14842 ) ).sort();
14843 }
14844
14845 // check for length avoids error when initializing empty list
14846 if ( this.options.active !== false && this.anchors.length ) {
14847 this.active = this._findActive( options.active );
14848 } else {
14849 this.active = $();
14850 }
14851
14852 this._refresh();
14853
14854 if ( this.active.length ) {
14855 this.load( options.active );
14856 }
14857 },
14858
14859 _initialActive: function() {
14860 var active = this.options.active,
14861 collapsible = this.options.collapsible,
14862 locationHash = location.hash.substring( 1 );
14863
14864 if ( active === null ) {
14865 // check the fragment identifier in the URL
14866 if ( locationHash ) {
14867 this.tabs.each(function( i, tab ) {
14868 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
14869 active = i;
14870 return false;
14871 }
14872 });
14873 }
14874
14875 // check for a tab marked active via a class
14876 if ( active === null ) {
14877 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
14878 }
14879
14880 // no active tab, set to false
14881 if ( active === null || active === -1 ) {
14882 active = this.tabs.length ? 0 : false;
14883 }
14884 }
14885
14886 // handle numbers: negative, out of range
14887 if ( active !== false ) {
14888 active = this.tabs.index( this.tabs.eq( active ) );
14889 if ( active === -1 ) {
14890 active = collapsible ? false : 0;
14891 }
14892 }
14893
14894 // don't allow collapsible: false and active: false
14895 if ( !collapsible && active === false && this.anchors.length ) {
14896 active = 0;
14897 }
14898
14899 return active;
14900 },
14901
14902 _getCreateEventData: function() {
14903 return {
14904 tab: this.active,
14905 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
14906 };
14907 },
14908
14909 _tabKeydown: function( event ) {
14910 /*jshint maxcomplexity:15*/
14911 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
14912 selectedIndex = this.tabs.index( focusedTab ),
14913 goingForward = true;
14914
14915 if ( this._handlePageNav( event ) ) {
14916 return;
14917 }
14918
14919 switch ( event.keyCode ) {
14920 case $.ui.keyCode.RIGHT:
14921 case $.ui.keyCode.DOWN:
14922 selectedIndex++;
14923 break;
14924 case $.ui.keyCode.UP:
14925 case $.ui.keyCode.LEFT:
14926 goingForward = false;
14927 selectedIndex--;
14928 break;
14929 case $.ui.keyCode.END:
14930 selectedIndex = this.anchors.length - 1;
14931 break;
14932 case $.ui.keyCode.HOME:
14933 selectedIndex = 0;
14934 break;
14935 case $.ui.keyCode.SPACE:
14936 // Activate only, no collapsing
14937 event.preventDefault();
14938 clearTimeout( this.activating );
14939 this._activate( selectedIndex );
14940 return;
14941 case $.ui.keyCode.ENTER:
14942 // Toggle (cancel delayed activation, allow collapsing)
14943 event.preventDefault();
14944 clearTimeout( this.activating );
14945 // Determine if we should collapse or activate
14946 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
14947 return;
14948 default:
14949 return;
14950 }
14951
14952 // Focus the appropriate tab, based on which key was pressed
14953 event.preventDefault();
14954 clearTimeout( this.activating );
14955 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
14956
14957 // Navigating with control key will prevent automatic activation
14958 if ( !event.ctrlKey ) {
14959 // Update aria-selected immediately so that AT think the tab is already selected.
14960 // Otherwise AT may confuse the user by stating that they need to activate the tab,
14961 // but the tab will already be activated by the time the announcement finishes.
14962 focusedTab.attr( "aria-selected", "false" );
14963 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
14964
14965 this.activating = this._delay(function() {
14966 this.option( "active", selectedIndex );
14967 }, this.delay );
14968 }
14969 },
14970
14971 _panelKeydown: function( event ) {
14972 if ( this._handlePageNav( event ) ) {
14973 return;
14974 }
14975
14976 // Ctrl+up moves focus to the current tab
14977 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
14978 event.preventDefault();
14979 this.active.focus();
14980 }
14981 },
14982
14983 // Alt+page up/down moves focus to the previous/next tab (and activates)
14984 _handlePageNav: function( event ) {
14985 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
14986 this._activate( this._focusNextTab( this.options.active - 1, false ) );
14987 return true;
14988 }
14989 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
14990 this._activate( this._focusNextTab( this.options.active + 1, true ) );
14991 return true;
14992 }
14993 },
14994
14995 _findNextTab: function( index, goingForward ) {
14996 var lastTabIndex = this.tabs.length - 1;
14997
14998 function constrain() {
14999 if ( index > lastTabIndex ) {
15000 index = 0;
15001 }
15002 if ( index < 0 ) {
15003 index = lastTabIndex;
15004 }
15005 return index;
15006 }
15007
15008 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
15009 index = goingForward ? index + 1 : index - 1;
15010 }
15011
15012 return index;
15013 },
15014
15015 _focusNextTab: function( index, goingForward ) {
15016 index = this._findNextTab( index, goingForward );
15017 this.tabs.eq( index ).focus();
15018 return index;
15019 },
15020
15021 _setOption: function( key, value ) {
15022 if ( key === "active" ) {
15023 // _activate() will handle invalid values and update this.options
15024 this._activate( value );
15025 return;
15026 }
15027
15028 if ( key === "disabled" ) {
15029 // don't use the widget factory's disabled handling
15030 this._setupDisabled( value );
15031 return;
15032 }
15033
15034 this._super( key, value);
15035
15036 if ( key === "collapsible" ) {
15037 this.element.toggleClass( "ui-tabs-collapsible", value );
15038 // Setting collapsible: false while collapsed; open first panel
15039 if ( !value && this.options.active === false ) {
15040 this._activate( 0 );
15041 }
15042 }
15043
15044 if ( key === "event" ) {
15045 this._setupEvents( value );
15046 }
15047
15048 if ( key === "heightStyle" ) {
15049 this._setupHeightStyle( value );
15050 }
15051 },
15052
15053 _tabId: function( tab ) {
15054 return tab.attr( "aria-controls" ) || "ui-tabs-" + getNextTabId();
15055 },
15056
15057 _sanitizeSelector: function( hash ) {
15058 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
15059 },
15060
15061 refresh: function() {
15062 var options = this.options,
15063 lis = this.tablist.children( ":has(a[href])" );
15064
15065 // get disabled tabs from class attribute from HTML
15066 // this will get converted to a boolean if needed in _refresh()
15067 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
15068 return lis.index( tab );
15069 });
15070
15071 this._processTabs();
15072
15073 // was collapsed or no tabs
15074 if ( options.active === false || !this.anchors.length ) {
15075 options.active = false;
15076 this.active = $();
15077 // was active, but active tab is gone
15078 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
15079 // all remaining tabs are disabled
15080 if ( this.tabs.length === options.disabled.length ) {
15081 options.active = false;
15082 this.active = $();
15083 // activate previous tab
15084 } else {
15085 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
15086 }
15087 // was active, active tab still exists
15088 } else {
15089 // make sure active index is correct
15090 options.active = this.tabs.index( this.active );
15091 }
15092
15093 this._refresh();
15094 },
15095
15096 _refresh: function() {
15097 this._setupDisabled( this.options.disabled );
15098 this._setupEvents( this.options.event );
15099 this._setupHeightStyle( this.options.heightStyle );
15100
15101 this.tabs.not( this.active ).attr({
15102 "aria-selected": "false",
15103 tabIndex: -1
15104 });
15105 this.panels.not( this._getPanelForTab( this.active ) )
15106 .hide()
15107 .attr({
15108 "aria-expanded": "false",
15109 "aria-hidden": "true"
15110 });
15111
15112 // Make sure one tab is in the tab order
15113 if ( !this.active.length ) {
15114 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
15115 } else {
15116 this.active
15117 .addClass( "ui-tabs-active ui-state-active" )
15118 .attr({
15119 "aria-selected": "true",
15120 tabIndex: 0
15121 });
15122 this._getPanelForTab( this.active )
15123 .show()
15124 .attr({
15125 "aria-expanded": "true",
15126 "aria-hidden": "false"
15127 });
15128 }
15129 },
15130
15131 _processTabs: function() {
15132 var that = this;
15133
15134 this.tablist = this._getList()
15135 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15136 .attr( "role", "tablist" );
15137
15138 this.tabs = this.tablist.find( "> li:has(a[href])" )
15139 .addClass( "ui-state-default ui-corner-top" )
15140 .attr({
15141 role: "tab",
15142 tabIndex: -1
15143 });
15144
15145 this.anchors = this.tabs.map(function() {
15146 return $( "a", this )[ 0 ];
15147 })
15148 .addClass( "ui-tabs-anchor" )
15149 .attr({
15150 role: "presentation",
15151 tabIndex: -1
15152 });
15153
15154 this.panels = $();
15155
15156 this.anchors.each(function( i, anchor ) {
15157 var selector, panel, panelId,
15158 anchorId = $( anchor ).uniqueId().attr( "id" ),
15159 tab = $( anchor ).closest( "li" ),
15160 originalAriaControls = tab.attr( "aria-controls" );
15161
15162 // inline tab
15163 if ( isLocal( anchor ) ) {
15164 selector = anchor.hash;
15165 panel = that.element.find( that._sanitizeSelector( selector ) );
15166 // remote tab
15167 } else {
15168 panelId = that._tabId( tab );
15169 selector = "#" + panelId;
15170 panel = that.element.find( selector );
15171 if ( !panel.length ) {
15172 panel = that._createPanel( panelId );
15173 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
15174 }
15175 panel.attr( "aria-live", "polite" );
15176 }
15177
15178 if ( panel.length) {
15179 that.panels = that.panels.add( panel );
15180 }
15181 if ( originalAriaControls ) {
15182 tab.data( "ui-tabs-aria-controls", originalAriaControls );
15183 }
15184 tab.attr({
15185 "aria-controls": selector.substring( 1 ),
15186 "aria-labelledby": anchorId
15187 });
15188 panel.attr( "aria-labelledby", anchorId );
15189 });
15190
15191 this.panels
15192 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15193 .attr( "role", "tabpanel" );
15194 },
15195
15196 // allow overriding how to find the list for rare usage scenarios (#7715)
15197 _getList: function() {
15198 return this.element.find( "ol,ul" ).eq( 0 );
15199 },
15200
15201 _createPanel: function( id ) {
15202 return $( "<div>" )
15203 .attr( "id", id )
15204 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
15205 .data( "ui-tabs-destroy", true );
15206 },
15207
15208 _setupDisabled: function( disabled ) {
15209 if ( $.isArray( disabled ) ) {
15210 if ( !disabled.length ) {
15211 disabled = false;
15212 } else if ( disabled.length === this.anchors.length ) {
15213 disabled = true;
15214 }
15215 }
15216
15217 // disable tabs
15218 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
15219 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
15220 $( li )
15221 .addClass( "ui-state-disabled" )
15222 .attr( "aria-disabled", "true" );
15223 } else {
15224 $( li )
15225 .removeClass( "ui-state-disabled" )
15226 .removeAttr( "aria-disabled" );
15227 }
15228 }
15229
15230 this.options.disabled = disabled;
15231 },
15232
15233 _setupEvents: function( event ) {
15234 var events = {
15235 click: function( event ) {
15236 event.preventDefault();
15237 }
15238 };
15239 if ( event ) {
15240 $.each( event.split(" "), function( index, eventName ) {
15241 events[ eventName ] = "_eventHandler";
15242 });
15243 }
15244
15245 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
15246 this._on( this.anchors, events );
15247 this._on( this.tabs, { keydown: "_tabKeydown" } );
15248 this._on( this.panels, { keydown: "_panelKeydown" } );
15249
15250 this._focusable( this.tabs );
15251 this._hoverable( this.tabs );
15252 },
15253
15254 _setupHeightStyle: function( heightStyle ) {
15255 var maxHeight,
15256 parent = this.element.parent();
15257
15258 if ( heightStyle === "fill" ) {
15259 maxHeight = parent.height();
15260 maxHeight -= this.element.outerHeight() - this.element.height();
15261
15262 this.element.siblings( ":visible" ).each(function() {
15263 var elem = $( this ),
15264 position = elem.css( "position" );
15265
15266 if ( position === "absolute" || position === "fixed" ) {
15267 return;
15268 }
15269 maxHeight -= elem.outerHeight( true );
15270 });
15271
15272 this.element.children().not( this.panels ).each(function() {
15273 maxHeight -= $( this ).outerHeight( true );
15274 });
15275
15276 this.panels.each(function() {
15277 $( this ).height( Math.max( 0, maxHeight -
15278 $( this ).innerHeight() + $( this ).height() ) );
15279 })
15280 .css( "overflow", "auto" );
15281 } else if ( heightStyle === "auto" ) {
15282 maxHeight = 0;
15283 this.panels.each(function() {
15284 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
15285 }).height( maxHeight );
15286 }
15287 },
15288
15289 _eventHandler: function( event ) {
15290 var options = this.options,
15291 active = this.active,
15292 anchor = $( event.currentTarget ),
15293 tab = anchor.closest( "li" ),
15294 clickedIsActive = tab[ 0 ] === active[ 0 ],
15295 collapsing = clickedIsActive && options.collapsible,
15296 toShow = collapsing ? $() : this._getPanelForTab( tab ),
15297 toHide = !active.length ? $() : this._getPanelForTab( active ),
15298 eventData = {
15299 oldTab: active,
15300 oldPanel: toHide,
15301 newTab: collapsing ? $() : tab,
15302 newPanel: toShow
15303 };
15304
15305 event.preventDefault();
15306
15307 if ( tab.hasClass( "ui-state-disabled" ) ||
15308 // tab is already loading
15309 tab.hasClass( "ui-tabs-loading" ) ||
15310 // can't switch durning an animation
15311 this.running ||
15312 // click on active header, but not collapsible
15313 ( clickedIsActive && !options.collapsible ) ||
15314 // allow canceling activation
15315 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
15316 return;
15317 }
15318
15319 options.active = collapsing ? false : this.tabs.index( tab );
15320
15321 this.active = clickedIsActive ? $() : tab;
15322 if ( this.xhr ) {
15323 this.xhr.abort();
15324 }
15325
15326 if ( !toHide.length && !toShow.length ) {
15327 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
15328 }
15329
15330 if ( toShow.length ) {
15331 this.load( this.tabs.index( tab ), event );
15332 }
15333 this._toggle( event, eventData );
15334 },
15335
15336 // handles show/hide for selecting tabs
15337 _toggle: function( event, eventData ) {
15338 var that = this,
15339 toShow = eventData.newPanel,
15340 toHide = eventData.oldPanel;
15341
15342 this.running = true;
15343
15344 function complete() {
15345 that.running = false;
15346 that._trigger( "activate", event, eventData );
15347 }
15348
15349 function show() {
15350 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
15351
15352 if ( toShow.length && that.options.show ) {
15353 that._show( toShow, that.options.show, complete );
15354 } else {
15355 toShow.show();
15356 complete();
15357 }
15358 }
15359
15360 // start out by hiding, then showing, then completing
15361 if ( toHide.length && this.options.hide ) {
15362 this._hide( toHide, this.options.hide, function() {
15363 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15364 show();
15365 });
15366 } else {
15367 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
15368 toHide.hide();
15369 show();
15370 }
15371
15372 toHide.attr({
15373 "aria-expanded": "false",
15374 "aria-hidden": "true"
15375 });
15376 eventData.oldTab.attr( "aria-selected", "false" );
15377 // If we're switching tabs, remove the old tab from the tab order.
15378 // If we're opening from collapsed state, remove the previous tab from the tab order.
15379 // If we're collapsing, then keep the collapsing tab in the tab order.
15380 if ( toShow.length && toHide.length ) {
15381 eventData.oldTab.attr( "tabIndex", -1 );
15382 } else if ( toShow.length ) {
15383 this.tabs.filter(function() {
15384 return $( this ).attr( "tabIndex" ) === 0;
15385 })
15386 .attr( "tabIndex", -1 );
15387 }
15388
15389 toShow.attr({
15390 "aria-expanded": "true",
15391 "aria-hidden": "false"
15392 });
15393 eventData.newTab.attr({
15394 "aria-selected": "true",
15395 tabIndex: 0
15396 });
15397 },
15398
15399 _activate: function( index ) {
15400 var anchor,
15401 active = this._findActive( index );
15402
15403 // trying to activate the already active panel
15404 if ( active[ 0 ] === this.active[ 0 ] ) {
15405 return;
15406 }
15407
15408 // trying to collapse, simulate a click on the current active header
15409 if ( !active.length ) {
15410 active = this.active;
15411 }
15412
15413 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
15414 this._eventHandler({
15415 target: anchor,
15416 currentTarget: anchor,
15417 preventDefault: $.noop
15418 });
15419 },
15420
15421 _findActive: function( index ) {
15422 return index === false ? $() : this.tabs.eq( index );
15423 },
15424
15425 _getIndex: function( index ) {
15426 // meta-function to give users option to provide a href string instead of a numerical index.
15427 if ( typeof index === "string" ) {
15428 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
15429 }
15430
15431 return index;
15432 },
15433
15434 _destroy: function() {
15435 if ( this.xhr ) {
15436 this.xhr.abort();
15437 }
15438
15439 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
15440
15441 this.tablist
15442 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
15443 .removeAttr( "role" );
15444
15445 this.anchors
15446 .removeClass( "ui-tabs-anchor" )
15447 .removeAttr( "role" )
15448 .removeAttr( "tabIndex" )
15449 .removeUniqueId();
15450
15451 this.tabs.add( this.panels ).each(function() {
15452 if ( $.data( this, "ui-tabs-destroy" ) ) {
15453 $( this ).remove();
15454 } else {
15455 $( this )
15456 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
15457 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
15458 .removeAttr( "tabIndex" )
15459 .removeAttr( "aria-live" )
15460 .removeAttr( "aria-busy" )
15461 .removeAttr( "aria-selected" )
15462 .removeAttr( "aria-labelledby" )
15463 .removeAttr( "aria-hidden" )
15464 .removeAttr( "aria-expanded" )
15465 .removeAttr( "role" );
15466 }
15467 });
15468
15469 this.tabs.each(function() {
15470 var li = $( this ),
15471 prev = li.data( "ui-tabs-aria-controls" );
15472 if ( prev ) {
15473 li
15474 .attr( "aria-controls", prev )
15475 .removeData( "ui-tabs-aria-controls" );
15476 } else {
15477 li.removeAttr( "aria-controls" );
15478 }
15479 });
15480
15481 this.panels.show();
15482
15483 if ( this.options.heightStyle !== "content" ) {
15484 this.panels.css( "height", "" );
15485 }
15486 },
15487
15488 enable: function( index ) {
15489 var disabled = this.options.disabled;
15490 if ( disabled === false ) {
15491 return;
15492 }
15493
15494 if ( index === undefined ) {
15495 disabled = false;
15496 } else {
15497 index = this._getIndex( index );
15498 if ( $.isArray( disabled ) ) {
15499 disabled = $.map( disabled, function( num ) {
15500 return num !== index ? num : null;
15501 });
15502 } else {
15503 disabled = $.map( this.tabs, function( li, num ) {
15504 return num !== index ? num : null;
15505 });
15506 }
15507 }
15508 this._setupDisabled( disabled );
15509 },
15510
15511 disable: function( index ) {
15512 var disabled = this.options.disabled;
15513 if ( disabled === true ) {
15514 return;
15515 }
15516
15517 if ( index === undefined ) {
15518 disabled = true;
15519 } else {
15520 index = this._getIndex( index );
15521 if ( $.inArray( index, disabled ) !== -1 ) {
15522 return;
15523 }
15524 if ( $.isArray( disabled ) ) {
15525 disabled = $.merge( [ index ], disabled ).sort();
15526 } else {
15527 disabled = [ index ];
15528 }
15529 }
15530 this._setupDisabled( disabled );
15531 },
15532
15533 load: function( index, event ) {
15534 index = this._getIndex( index );
15535 var that = this,
15536 tab = this.tabs.eq( index ),
15537 anchor = tab.find( ".ui-tabs-anchor" ),
15538 panel = this._getPanelForTab( tab ),
15539 eventData = {
15540 tab: tab,
15541 panel: panel
15542 };
15543
15544 // not remote
15545 if ( isLocal( anchor[ 0 ] ) ) {
15546 return;
15547 }
15548
15549 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
15550
15551 // support: jQuery <1.8
15552 // jQuery <1.8 returns false if the request is canceled in beforeSend,
15553 // but as of 1.8, $.ajax() always returns a jqXHR object.
15554 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
15555 tab.addClass( "ui-tabs-loading" );
15556 panel.attr( "aria-busy", "true" );
15557
15558 this.xhr
15559 .success(function( response ) {
15560 // support: jQuery <1.8
15561 // http://bugs.jquery.com/ticket/11778
15562 setTimeout(function() {
15563 panel.html( response );
15564 that._trigger( "load", event, eventData );
15565 }, 1 );
15566 })
15567 .complete(function( jqXHR, status ) {
15568 // support: jQuery <1.8
15569 // http://bugs.jquery.com/ticket/11778
15570 setTimeout(function() {
15571 if ( status === "abort" ) {
15572 that.panels.stop( false, true );
15573 }
15574
15575 tab.removeClass( "ui-tabs-loading" );
15576 panel.removeAttr( "aria-busy" );
15577
15578 if ( jqXHR === that.xhr ) {
15579 delete that.xhr;
15580 }
15581 }, 1 );
15582 });
15583 }
15584 },
15585
15586 _ajaxSettings: function( anchor, event, eventData ) {
15587 var that = this;
15588 return {
15589 url: anchor.attr( "href" ),
15590 beforeSend: function( jqXHR, settings ) {
15591 return that._trigger( "beforeLoad", event,
15592 $.extend( { jqXHR : jqXHR, ajaxSettings: settings }, eventData ) );
15593 }
15594 };
15595 },
15596
15597 _getPanelForTab: function( tab ) {
15598 var id = $( tab ).attr( "aria-controls" );
15599 return this.element.find( this._sanitizeSelector( "#" + id ) );
15600 }
15601 });
15602
15603 })( jQuery );
15604 (function( $ ) {
15605
15606 var increments = 0;
15607
15608 function addDescribedBy( elem, id ) {
15609 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
15610 describedby.push( id );
15611 elem
15612 .data( "ui-tooltip-id", id )
15613 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
15614 }
15615
15616 function removeDescribedBy( elem ) {
15617 var id = elem.data( "ui-tooltip-id" ),
15618 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
15619 index = $.inArray( id, describedby );
15620 if ( index !== -1 ) {
15621 describedby.splice( index, 1 );
15622 }
15623
15624 elem.removeData( "ui-tooltip-id" );
15625 describedby = $.trim( describedby.join( " " ) );
15626 if ( describedby ) {
15627 elem.attr( "aria-describedby", describedby );
15628 } else {
15629 elem.removeAttr( "aria-describedby" );
15630 }
15631 }
15632
15633 $.widget( "ui.tooltip", {
15634 version: "1.10.3",
15635 options: {
15636 content: function() {
15637 // support: IE<9, Opera in jQuery <1.7
15638 // .text() can't accept undefined, so coerce to a string
15639 var title = $( this ).attr( "title" ) || "";
15640 // Escape title, since we're going from an attribute to raw HTML
15641 return $( "<a>" ).text( title ).html();
15642 },
15643 hide: true,
15644 // Disabled elements have inconsistent behavior across browsers (#8661)
15645 items: "[title]:not([disabled])",
15646 position: {
15647 my: "left top+15",
15648 at: "left bottom",
15649 collision: "flipfit flip"
15650 },
15651 show: true,
15652 tooltipClass: null,
15653 track: false,
15654
15655 // callbacks
15656 close: null,
15657 open: null
15658 },
15659
15660 _create: function() {
15661 this._on({
15662 mouseover: "open",
15663 focusin: "open"
15664 });
15665
15666 // IDs of generated tooltips, needed for destroy
15667 this.tooltips = {};
15668 // IDs of parent tooltips where we removed the title attribute
15669 this.parents = {};
15670
15671 if ( this.options.disabled ) {
15672 this._disable();
15673 }
15674 },
15675
15676 _setOption: function( key, value ) {
15677 var that = this;
15678
15679 if ( key === "disabled" ) {
15680 this[ value ? "_disable" : "_enable" ]();
15681 this.options[ key ] = value;
15682 // disable element style changes
15683 return;
15684 }
15685
15686 this._super( key, value );
15687
15688 if ( key === "content" ) {
15689 $.each( this.tooltips, function( id, element ) {
15690 that._updateContent( element );
15691 });
15692 }
15693 },
15694
15695 _disable: function() {
15696 var that = this;
15697
15698 // close open tooltips
15699 $.each( this.tooltips, function( id, element ) {
15700 var event = $.Event( "blur" );
15701 event.target = event.currentTarget = element[0];
15702 that.close( event, true );
15703 });
15704
15705 // remove title attributes to prevent native tooltips
15706 this.element.find( this.options.items ).addBack().each(function() {
15707 var element = $( this );
15708 if ( element.is( "[title]" ) ) {
15709 element
15710 .data( "ui-tooltip-title", element.attr( "title" ) )
15711 .attr( "title", "" );
15712 }
15713 });
15714 },
15715
15716 _enable: function() {
15717 // restore title attributes
15718 this.element.find( this.options.items ).addBack().each(function() {
15719 var element = $( this );
15720 if ( element.data( "ui-tooltip-title" ) ) {
15721 element.attr( "title", element.data( "ui-tooltip-title" ) );
15722 }
15723 });
15724 },
15725
15726 open: function( event ) {
15727 var that = this,
15728 target = $( event ? event.target : this.element )
15729 // we need closest here due to mouseover bubbling,
15730 // but always pointing at the same event target
15731 .closest( this.options.items );
15732
15733 // No element to show a tooltip for or the tooltip is already open
15734 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
15735 return;
15736 }
15737
15738 if ( target.attr( "title" ) ) {
15739 target.data( "ui-tooltip-title", target.attr( "title" ) );
15740 }
15741
15742 target.data( "ui-tooltip-open", true );
15743
15744 // kill parent tooltips, custom or native, for hover
15745 if ( event && event.type === "mouseover" ) {
15746 target.parents().each(function() {
15747 var parent = $( this ),
15748 blurEvent;
15749 if ( parent.data( "ui-tooltip-open" ) ) {
15750 blurEvent = $.Event( "blur" );
15751 blurEvent.target = blurEvent.currentTarget = this;
15752 that.close( blurEvent, true );
15753 }
15754 if ( parent.attr( "title" ) ) {
15755 parent.uniqueId();
15756 that.parents[ this.id ] = {
15757 element: this,
15758 title: parent.attr( "title" )
15759 };
15760 parent.attr( "title", "" );
15761 }
15762 });
15763 }
15764
15765 this._updateContent( target, event );
15766 },
15767
15768 _updateContent: function( target, event ) {
15769 var content,
15770 contentOption = this.options.content,
15771 that = this,
15772 eventType = event ? event.type : null;
15773
15774 if ( typeof contentOption === "string" ) {
15775 return this._open( event, target, contentOption );
15776 }
15777
15778 content = contentOption.call( target[0], function( response ) {
15779 // ignore async response if tooltip was closed already
15780 if ( !target.data( "ui-tooltip-open" ) ) {
15781 return;
15782 }
15783 // IE may instantly serve a cached response for ajax requests
15784 // delay this call to _open so the other call to _open runs first
15785 that._delay(function() {
15786 // jQuery creates a special event for focusin when it doesn't
15787 // exist natively. To improve performance, the native event
15788 // object is reused and the type is changed. Therefore, we can't
15789 // rely on the type being correct after the event finished
15790 // bubbling, so we set it back to the previous value. (#8740)
15791 if ( event ) {
15792 event.type = eventType;
15793 }
15794 this._open( event, target, response );
15795 });
15796 });
15797 if ( content ) {
15798 this._open( event, target, content );
15799 }
15800 },
15801
15802 _open: function( event, target, content ) {
15803 var tooltip, events, delayedShow,
15804 positionOption = $.extend( {}, this.options.position );
15805
15806 if ( !content ) {
15807 return;
15808 }
15809
15810 // Content can be updated multiple times. If the tooltip already
15811 // exists, then just update the content and bail.
15812 tooltip = this._find( target );
15813 if ( tooltip.length ) {
15814 tooltip.find( ".ui-tooltip-content" ).html( content );
15815 return;
15816 }
15817
15818 // if we have a title, clear it to prevent the native tooltip
15819 // we have to check first to avoid defining a title if none exists
15820 // (we don't want to cause an element to start matching [title])
15821 //
15822 // We use removeAttr only for key events, to allow IE to export the correct
15823 // accessible attributes. For mouse events, set to empty string to avoid
15824 // native tooltip showing up (happens only when removing inside mouseover).
15825 if ( target.is( "[title]" ) ) {
15826 if ( event && event.type === "mouseover" ) {
15827 target.attr( "title", "" );
15828 } else {
15829 target.removeAttr( "title" );
15830 }
15831 }
15832
15833 tooltip = this._tooltip( target );
15834 addDescribedBy( target, tooltip.attr( "id" ) );
15835 tooltip.find( ".ui-tooltip-content" ).html( content );
15836
15837 function position( event ) {
15838 positionOption.of = event;
15839 if ( tooltip.is( ":hidden" ) ) {
15840 return;
15841 }
15842 tooltip.position( positionOption );
15843 }
15844 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
15845 this._on( this.document, {
15846 mousemove: position
15847 });
15848 // trigger once to override element-relative positioning
15849 position( event );
15850 } else {
15851 tooltip.position( $.extend({
15852 of: target
15853 }, this.options.position ) );
15854 }
15855
15856 tooltip.hide();
15857
15858 this._show( tooltip, this.options.show );
15859 // Handle tracking tooltips that are shown with a delay (#8644). As soon
15860 // as the tooltip is visible, position the tooltip using the most recent
15861 // event.
15862 if ( this.options.show && this.options.show.delay ) {
15863 delayedShow = this.delayedShow = setInterval(function() {
15864 if ( tooltip.is( ":visible" ) ) {
15865 position( positionOption.of );
15866 clearInterval( delayedShow );
15867 }
15868 }, $.fx.interval );
15869 }
15870
15871 this._trigger( "open", event, { tooltip: tooltip } );
15872
15873 events = {
15874 keyup: function( event ) {
15875 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
15876 var fakeEvent = $.Event(event);
15877 fakeEvent.currentTarget = target[0];
15878 this.close( fakeEvent, true );
15879 }
15880 },
15881 remove: function() {
15882 this._removeTooltip( tooltip );
15883 }
15884 };
15885 if ( !event || event.type === "mouseover" ) {
15886 events.mouseleave = "close";
15887 }
15888 if ( !event || event.type === "focusin" ) {
15889 events.focusout = "close";
15890 }
15891 this._on( true, target, events );
15892 },
15893
15894 close: function( event ) {
15895 var that = this,
15896 target = $( event ? event.currentTarget : this.element ),
15897 tooltip = this._find( target );
15898
15899 // disabling closes the tooltip, so we need to track when we're closing
15900 // to avoid an infinite loop in case the tooltip becomes disabled on close
15901 if ( this.closing ) {
15902 return;
15903 }
15904
15905 // Clear the interval for delayed tracking tooltips
15906 clearInterval( this.delayedShow );
15907
15908 // only set title if we had one before (see comment in _open())
15909 if ( target.data( "ui-tooltip-title" ) ) {
15910 target.attr( "title", target.data( "ui-tooltip-title" ) );
15911 }
15912
15913 removeDescribedBy( target );
15914
15915 tooltip.stop( true );
15916 this._hide( tooltip, this.options.hide, function() {
15917 that._removeTooltip( $( this ) );
15918 });
15919
15920 target.removeData( "ui-tooltip-open" );
15921 this._off( target, "mouseleave focusout keyup" );
15922 // Remove 'remove' binding only on delegated targets
15923 if ( target[0] !== this.element[0] ) {
15924 this._off( target, "remove" );
15925 }
15926 this._off( this.document, "mousemove" );
15927
15928 if ( event && event.type === "mouseleave" ) {
15929 $.each( this.parents, function( id, parent ) {
15930 $( parent.element ).attr( "title", parent.title );
15931 delete that.parents[ id ];
15932 });
15933 }
15934
15935 this.closing = true;
15936 this._trigger( "close", event, { tooltip: tooltip } );
15937 this.closing = false;
15938 },
15939
15940 _tooltip: function( element ) {
15941 var id = "ui-tooltip-" + increments++,
15942 tooltip = $( "<div>" )
15943 .attr({
15944 id: id,
15945 role: "tooltip"
15946 })
15947 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
15948 ( this.options.tooltipClass || "" ) );
15949 $( "<div>" )
15950 .addClass( "ui-tooltip-content" )
15951 .appendTo( tooltip );
15952 tooltip.appendTo( this.document[0].body );
15953 this.tooltips[ id ] = element;
15954 return tooltip;
15955 },
15956
15957 _find: function( target ) {
15958 var id = target.data( "ui-tooltip-id" );
15959 return id ? $( "#" + id ) : $();
15960 },
15961
15962 _removeTooltip: function( tooltip ) {
15963 tooltip.remove();
15964 delete this.tooltips[ tooltip.attr( "id" ) ];
15965 },
15966
15967 _destroy: function() {
15968 var that = this;
15969
15970 // close open tooltips
15971 $.each( this.tooltips, function( id, element ) {
15972 // Delegate to close method to handle common cleanup
15973 var event = $.Event( "blur" );
15974 event.target = event.currentTarget = element[0];
15975 that.close( event, true );
15976
15977 // Remove immediately; destroying an open tooltip doesn't use the
15978 // hide animation
15979 $( "#" + id ).remove();
15980
15981 // Restore the title
15982 if ( element.data( "ui-tooltip-title" ) ) {
15983 element.attr( "title", element.data( "ui-tooltip-title" ) );
15984 element.removeData( "ui-tooltip-title" );
15985 }
15986 });
15987 }
15988 });
15989
15990 }( jQuery ) );
15991 (function($, undefined) {
15992
15993 var dataSpace = "ui-effects-";
15994
15995 $.effects = {
15996 effect: {}
15997 };
15998
15999 /*!
16000 * jQuery Color Animations v2.1.2
16001 * https://github.com/jquery/jquery-color
16002 *
16003 * Copyright 2013 jQuery Foundation and other contributors
16004 * Released under the MIT license.
16005 * http://jquery.org/license
16006 *
16007 * Date: Wed Jan 16 08:47:09 2013 -0600
16008 */
16009 (function( jQuery, undefined ) {
16010
16011 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
16012
16013 // plusequals test for += 100 -= 100
16014 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
16015 // a set of RE's that can match strings and generate color tuples.
16016 stringParsers = [{
16017 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
16018 parse: function( execResult ) {
16019 return [
16020 execResult[ 1 ],
16021 execResult[ 2 ],
16022 execResult[ 3 ],
16023 execResult[ 4 ]
16024 ];
16025 }
16026 }, {
16027 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
16028 parse: function( execResult ) {
16029 return [
16030 execResult[ 1 ] * 2.55,
16031 execResult[ 2 ] * 2.55,
16032 execResult[ 3 ] * 2.55,
16033 execResult[ 4 ]
16034 ];
16035 }
16036 }, {
16037 // this regex ignores A-F because it's compared against an already lowercased string
16038 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
16039 parse: function( execResult ) {
16040 return [
16041 parseInt( execResult[ 1 ], 16 ),
16042 parseInt( execResult[ 2 ], 16 ),
16043 parseInt( execResult[ 3 ], 16 )
16044 ];
16045 }
16046 }, {
16047 // this regex ignores A-F because it's compared against an already lowercased string
16048 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
16049 parse: function( execResult ) {
16050 return [
16051 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
16052 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
16053 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
16054 ];
16055 }
16056 }, {
16057 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
16058 space: "hsla",
16059 parse: function( execResult ) {
16060 return [
16061 execResult[ 1 ],
16062 execResult[ 2 ] / 100,
16063 execResult[ 3 ] / 100,
16064 execResult[ 4 ]
16065 ];
16066 }
16067 }],
16068
16069 // jQuery.Color( )
16070 color = jQuery.Color = function( color, green, blue, alpha ) {
16071 return new jQuery.Color.fn.parse( color, green, blue, alpha );
16072 },
16073 spaces = {
16074 rgba: {
16075 props: {
16076 red: {
16077 idx: 0,
16078 type: "byte"
16079 },
16080 green: {
16081 idx: 1,
16082 type: "byte"
16083 },
16084 blue: {
16085 idx: 2,
16086 type: "byte"
16087 }
16088 }
16089 },
16090
16091 hsla: {
16092 props: {
16093 hue: {
16094 idx: 0,
16095 type: "degrees"
16096 },
16097 saturation: {
16098 idx: 1,
16099 type: "percent"
16100 },
16101 lightness: {
16102 idx: 2,
16103 type: "percent"
16104 }
16105 }
16106 }
16107 },
16108 propTypes = {
16109 "byte": {
16110 floor: true,
16111 max: 255
16112 },
16113 "percent": {
16114 max: 1
16115 },
16116 "degrees": {
16117 mod: 360,
16118 floor: true
16119 }
16120 },
16121 support = color.support = {},
16122
16123 // element for support tests
16124 supportElem = jQuery( "<p>" )[ 0 ],
16125
16126 // colors = jQuery.Color.names
16127 colors,
16128
16129 // local aliases of functions called often
16130 each = jQuery.each;
16131
16132 // determine rgba support immediately
16133 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
16134 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
16135
16136 // define cache name and alpha properties
16137 // for rgba and hsla spaces
16138 each( spaces, function( spaceName, space ) {
16139 space.cache = "_" + spaceName;
16140 space.props.alpha = {
16141 idx: 3,
16142 type: "percent",
16143 def: 1
16144 };
16145 });
16146
16147 function clamp( value, prop, allowEmpty ) {
16148 var type = propTypes[ prop.type ] || {};
16149
16150 if ( value == null ) {
16151 return (allowEmpty || !prop.def) ? null : prop.def;
16152 }
16153
16154 // ~~ is an short way of doing floor for positive numbers
16155 value = type.floor ? ~~value : parseFloat( value );
16156
16157 // IE will pass in empty strings as value for alpha,
16158 // which will hit this case
16159 if ( isNaN( value ) ) {
16160 return prop.def;
16161 }
16162
16163 if ( type.mod ) {
16164 // we add mod before modding to make sure that negatives values
16165 // get converted properly: -10 -> 350
16166 return (value + type.mod) % type.mod;
16167 }
16168
16169 // for now all property types without mod have min and max
16170 return 0 > value ? 0 : type.max < value ? type.max : value;
16171 }
16172
16173 function stringParse( string ) {
16174 var inst = color(),
16175 rgba = inst._rgba = [];
16176
16177 string = string.toLowerCase();
16178
16179 each( stringParsers, function( i, parser ) {
16180 var parsed,
16181 match = parser.re.exec( string ),
16182 values = match && parser.parse( match ),
16183 spaceName = parser.space || "rgba";
16184
16185 if ( values ) {
16186 parsed = inst[ spaceName ]( values );
16187
16188 // if this was an rgba parse the assignment might happen twice
16189 // oh well....
16190 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
16191 rgba = inst._rgba = parsed._rgba;
16192
16193 // exit each( stringParsers ) here because we matched
16194 return false;
16195 }
16196 });
16197
16198 // Found a stringParser that handled it
16199 if ( rgba.length ) {
16200
16201 // if this came from a parsed string, force "transparent" when alpha is 0
16202 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
16203 if ( rgba.join() === "0,0,0,0" ) {
16204 jQuery.extend( rgba, colors.transparent );
16205 }
16206 return inst;
16207 }
16208
16209 // named colors
16210 return colors[ string ];
16211 }
16212
16213 color.fn = jQuery.extend( color.prototype, {
16214 parse: function( red, green, blue, alpha ) {
16215 if ( red === undefined ) {
16216 this._rgba = [ null, null, null, null ];
16217 return this;
16218 }
16219 if ( red.jquery || red.nodeType ) {
16220 red = jQuery( red ).css( green );
16221 green = undefined;
16222 }
16223
16224 var inst = this,
16225 type = jQuery.type( red ),
16226 rgba = this._rgba = [];
16227
16228 // more than 1 argument specified - assume ( red, green, blue, alpha )
16229 if ( green !== undefined ) {
16230 red = [ red, green, blue, alpha ];
16231 type = "array";
16232 }
16233
16234 if ( type === "string" ) {
16235 return this.parse( stringParse( red ) || colors._default );
16236 }
16237
16238 if ( type === "array" ) {
16239 each( spaces.rgba.props, function( key, prop ) {
16240 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
16241 });
16242 return this;
16243 }
16244
16245 if ( type === "object" ) {
16246 if ( red instanceof color ) {
16247 each( spaces, function( spaceName, space ) {
16248 if ( red[ space.cache ] ) {
16249 inst[ space.cache ] = red[ space.cache ].slice();
16250 }
16251 });
16252 } else {
16253 each( spaces, function( spaceName, space ) {
16254 var cache = space.cache;
16255 each( space.props, function( key, prop ) {
16256
16257 // if the cache doesn't exist, and we know how to convert
16258 if ( !inst[ cache ] && space.to ) {
16259
16260 // if the value was null, we don't need to copy it
16261 // if the key was alpha, we don't need to copy it either
16262 if ( key === "alpha" || red[ key ] == null ) {
16263 return;
16264 }
16265 inst[ cache ] = space.to( inst._rgba );
16266 }
16267
16268 // this is the only case where we allow nulls for ALL properties.
16269 // call clamp with alwaysAllowEmpty
16270 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
16271 });
16272
16273 // everything defined but alpha?
16274 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
16275 // use the default of 1
16276 inst[ cache ][ 3 ] = 1;
16277 if ( space.from ) {
16278 inst._rgba = space.from( inst[ cache ] );
16279 }
16280 }
16281 });
16282 }
16283 return this;
16284 }
16285 },
16286 is: function( compare ) {
16287 var is = color( compare ),
16288 same = true,
16289 inst = this;
16290
16291 each( spaces, function( _, space ) {
16292 var localCache,
16293 isCache = is[ space.cache ];
16294 if (isCache) {
16295 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
16296 each( space.props, function( _, prop ) {
16297 if ( isCache[ prop.idx ] != null ) {
16298 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
16299 return same;
16300 }
16301 });
16302 }
16303 return same;
16304 });
16305 return same;
16306 },
16307 _space: function() {
16308 var used = [],
16309 inst = this;
16310 each( spaces, function( spaceName, space ) {
16311 if ( inst[ space.cache ] ) {
16312 used.push( spaceName );
16313 }
16314 });
16315 return used.pop();
16316 },
16317 transition: function( other, distance ) {
16318 var end = color( other ),
16319 spaceName = end._space(),
16320 space = spaces[ spaceName ],
16321 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
16322 start = startColor[ space.cache ] || space.to( startColor._rgba ),
16323 result = start.slice();
16324
16325 end = end[ space.cache ];
16326 each( space.props, function( key, prop ) {
16327 var index = prop.idx,
16328 startValue = start[ index ],
16329 endValue = end[ index ],
16330 type = propTypes[ prop.type ] || {};
16331
16332 // if null, don't override start value
16333 if ( endValue === null ) {
16334 return;
16335 }
16336 // if null - use end
16337 if ( startValue === null ) {
16338 result[ index ] = endValue;
16339 } else {
16340 if ( type.mod ) {
16341 if ( endValue - startValue > type.mod / 2 ) {
16342 startValue += type.mod;
16343 } else if ( startValue - endValue > type.mod / 2 ) {
16344 startValue -= type.mod;
16345 }
16346 }
16347 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
16348 }
16349 });
16350 return this[ spaceName ]( result );
16351 },
16352 blend: function( opaque ) {
16353 // if we are already opaque - return ourself
16354 if ( this._rgba[ 3 ] === 1 ) {
16355 return this;
16356 }
16357
16358 var rgb = this._rgba.slice(),
16359 a = rgb.pop(),
16360 blend = color( opaque )._rgba;
16361
16362 return color( jQuery.map( rgb, function( v, i ) {
16363 return ( 1 - a ) * blend[ i ] + a * v;
16364 }));
16365 },
16366 toRgbaString: function() {
16367 var prefix = "rgba(",
16368 rgba = jQuery.map( this._rgba, function( v, i ) {
16369 return v == null ? ( i > 2 ? 1 : 0 ) : v;
16370 });
16371
16372 if ( rgba[ 3 ] === 1 ) {
16373 rgba.pop();
16374 prefix = "rgb(";
16375 }
16376
16377 return prefix + rgba.join() + ")";
16378 },
16379 toHslaString: function() {
16380 var prefix = "hsla(",
16381 hsla = jQuery.map( this.hsla(), function( v, i ) {
16382 if ( v == null ) {
16383 v = i > 2 ? 1 : 0;
16384 }
16385
16386 // catch 1 and 2
16387 if ( i && i < 3 ) {
16388 v = Math.round( v * 100 ) + "%";
16389 }
16390 return v;
16391 });
16392
16393 if ( hsla[ 3 ] === 1 ) {
16394 hsla.pop();
16395 prefix = "hsl(";
16396 }
16397 return prefix + hsla.join() + ")";
16398 },
16399 toHexString: function( includeAlpha ) {
16400 var rgba = this._rgba.slice(),
16401 alpha = rgba.pop();
16402
16403 if ( includeAlpha ) {
16404 rgba.push( ~~( alpha * 255 ) );
16405 }
16406
16407 return "#" + jQuery.map( rgba, function( v ) {
16408
16409 // default to 0 when nulls exist
16410 v = ( v || 0 ).toString( 16 );
16411 return v.length === 1 ? "0" + v : v;
16412 }).join("");
16413 },
16414 toString: function() {
16415 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
16416 }
16417 });
16418 color.fn.parse.prototype = color.fn;
16419
16420 // hsla conversions adapted from:
16421 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
16422
16423 function hue2rgb( p, q, h ) {
16424 h = ( h + 1 ) % 1;
16425 if ( h * 6 < 1 ) {
16426 return p + (q - p) * h * 6;
16427 }
16428 if ( h * 2 < 1) {
16429 return q;
16430 }
16431 if ( h * 3 < 2 ) {
16432 return p + (q - p) * ((2/3) - h) * 6;
16433 }
16434 return p;
16435 }
16436
16437 spaces.hsla.to = function ( rgba ) {
16438 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
16439 return [ null, null, null, rgba[ 3 ] ];
16440 }
16441 var r = rgba[ 0 ] / 255,
16442 g = rgba[ 1 ] / 255,
16443 b = rgba[ 2 ] / 255,
16444 a = rgba[ 3 ],
16445 max = Math.max( r, g, b ),
16446 min = Math.min( r, g, b ),
16447 diff = max - min,
16448 add = max + min,
16449 l = add * 0.5,
16450 h, s;
16451
16452 if ( min === max ) {
16453 h = 0;
16454 } else if ( r === max ) {
16455 h = ( 60 * ( g - b ) / diff ) + 360;
16456 } else if ( g === max ) {
16457 h = ( 60 * ( b - r ) / diff ) + 120;
16458 } else {
16459 h = ( 60 * ( r - g ) / diff ) + 240;
16460 }
16461
16462 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
16463 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
16464 if ( diff === 0 ) {
16465 s = 0;
16466 } else if ( l <= 0.5 ) {
16467 s = diff / add;
16468 } else {
16469 s = diff / ( 2 - add );
16470 }
16471 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
16472 };
16473
16474 spaces.hsla.from = function ( hsla ) {
16475 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
16476 return [ null, null, null, hsla[ 3 ] ];
16477 }
16478 var h = hsla[ 0 ] / 360,
16479 s = hsla[ 1 ],
16480 l = hsla[ 2 ],
16481 a = hsla[ 3 ],
16482 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
16483 p = 2 * l - q;
16484
16485 return [
16486 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
16487 Math.round( hue2rgb( p, q, h ) * 255 ),
16488 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
16489 a
16490 ];
16491 };
16492
16493
16494 each( spaces, function( spaceName, space ) {
16495 var props = space.props,
16496 cache = space.cache,
16497 to = space.to,
16498 from = space.from;
16499
16500 // makes rgba() and hsla()
16501 color.fn[ spaceName ] = function( value ) {
16502
16503 // generate a cache for this space if it doesn't exist
16504 if ( to && !this[ cache ] ) {
16505 this[ cache ] = to( this._rgba );
16506 }
16507 if ( value === undefined ) {
16508 return this[ cache ].slice();
16509 }
16510
16511 var ret,
16512 type = jQuery.type( value ),
16513 arr = ( type === "array" || type === "object" ) ? value : arguments,
16514 local = this[ cache ].slice();
16515
16516 each( props, function( key, prop ) {
16517 var val = arr[ type === "object" ? key : prop.idx ];
16518 if ( val == null ) {
16519 val = local[ prop.idx ];
16520 }
16521 local[ prop.idx ] = clamp( val, prop );
16522 });
16523
16524 if ( from ) {
16525 ret = color( from( local ) );
16526 ret[ cache ] = local;
16527 return ret;
16528 } else {
16529 return color( local );
16530 }
16531 };
16532
16533 // makes red() green() blue() alpha() hue() saturation() lightness()
16534 each( props, function( key, prop ) {
16535 // alpha is included in more than one space
16536 if ( color.fn[ key ] ) {
16537 return;
16538 }
16539 color.fn[ key ] = function( value ) {
16540 var vtype = jQuery.type( value ),
16541 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
16542 local = this[ fn ](),
16543 cur = local[ prop.idx ],
16544 match;
16545
16546 if ( vtype === "undefined" ) {
16547 return cur;
16548 }
16549
16550 if ( vtype === "function" ) {
16551 value = value.call( this, cur );
16552 vtype = jQuery.type( value );
16553 }
16554 if ( value == null && prop.empty ) {
16555 return this;
16556 }
16557 if ( vtype === "string" ) {
16558 match = rplusequals.exec( value );
16559 if ( match ) {
16560 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
16561 }
16562 }
16563 local[ prop.idx ] = value;
16564 return this[ fn ]( local );
16565 };
16566 });
16567 });
16568
16569 // add cssHook and .fx.step function for each named hook.
16570 // accept a space separated string of properties
16571 color.hook = function( hook ) {
16572 var hooks = hook.split( " " );
16573 each( hooks, function( i, hook ) {
16574 jQuery.cssHooks[ hook ] = {
16575 set: function( elem, value ) {
16576 var parsed, curElem,
16577 backgroundColor = "";
16578
16579 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
16580 value = color( parsed || value );
16581 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
16582 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
16583 while (
16584 (backgroundColor === "" || backgroundColor === "transparent") &&
16585 curElem && curElem.style
16586 ) {
16587 try {
16588 backgroundColor = jQuery.css( curElem, "backgroundColor" );
16589 curElem = curElem.parentNode;
16590 } catch ( e ) {
16591 }
16592 }
16593
16594 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
16595 backgroundColor :
16596 "_default" );
16597 }
16598
16599 value = value.toRgbaString();
16600 }
16601 try {
16602 elem.style[ hook ] = value;
16603 } catch( e ) {
16604 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
16605 }
16606 }
16607 };
16608 jQuery.fx.step[ hook ] = function( fx ) {
16609 if ( !fx.colorInit ) {
16610 fx.start = color( fx.elem, hook );
16611 fx.end = color( fx.end );
16612 fx.colorInit = true;
16613 }
16614 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
16615 };
16616 });
16617
16618 };
16619
16620 color.hook( stepHooks );
16621
16622 jQuery.cssHooks.borderColor = {
16623 expand: function( value ) {
16624 var expanded = {};
16625
16626 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
16627 expanded[ "border" + part + "Color" ] = value;
16628 });
16629 return expanded;
16630 }
16631 };
16632
16633 // Basic color names only.
16634 // Usage of any of the other color names requires adding yourself or including
16635 // jquery.color.svg-names.js.
16636 colors = jQuery.Color.names = {
16637 // 4.1. Basic color keywords
16638 aqua: "#00ffff",
16639 black: "#000000",
16640 blue: "#0000ff",
16641 fuchsia: "#ff00ff",
16642 gray: "#808080",
16643 green: "#008000",
16644 lime: "#00ff00",
16645 maroon: "#800000",
16646 navy: "#000080",
16647 olive: "#808000",
16648 purple: "#800080",
16649 red: "#ff0000",
16650 silver: "#c0c0c0",
16651 teal: "#008080",
16652 white: "#ffffff",
16653 yellow: "#ffff00",
16654
16655 // 4.2.3. "transparent" color keyword
16656 transparent: [ null, null, null, 0 ],
16657
16658 _default: "#ffffff"
16659 };
16660
16661 })( jQuery );
16662
16663
16664 /******************************************************************************/
16665 /****************************** CLASS ANIMATIONS ******************************/
16666 /******************************************************************************/
16667 (function() {
16668
16669 var classAnimationActions = [ "add", "remove", "toggle" ],
16670 shorthandStyles = {
16671 border: 1,
16672 borderBottom: 1,
16673 borderColor: 1,
16674 borderLeft: 1,
16675 borderRight: 1,
16676 borderTop: 1,
16677 borderWidth: 1,
16678 margin: 1,
16679 padding: 1
16680 };
16681
16682 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
16683 $.fx.step[ prop ] = function( fx ) {
16684 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
16685 jQuery.style( fx.elem, prop, fx.end );
16686 fx.setAttr = true;
16687 }
16688 };
16689 });
16690
16691 function getElementStyles( elem ) {
16692 var key, len,
16693 style = elem.ownerDocument.defaultView ?
16694 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
16695 elem.currentStyle,
16696 styles = {};
16697
16698 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
16699 len = style.length;
16700 while ( len-- ) {
16701 key = style[ len ];
16702 if ( typeof style[ key ] === "string" ) {
16703 styles[ $.camelCase( key ) ] = style[ key ];
16704 }
16705 }
16706 // support: Opera, IE <9
16707 } else {
16708 for ( key in style ) {
16709 if ( typeof style[ key ] === "string" ) {
16710 styles[ key ] = style[ key ];
16711 }
16712 }
16713 }
16714
16715 return styles;
16716 }
16717
16718
16719 function styleDifference( oldStyle, newStyle ) {
16720 var diff = {},
16721 name, value;
16722
16723 for ( name in newStyle ) {
16724 value = newStyle[ name ];
16725 if ( oldStyle[ name ] !== value ) {
16726 if ( !shorthandStyles[ name ] ) {
16727 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
16728 diff[ name ] = value;
16729 }
16730 }
16731 }
16732 }
16733
16734 return diff;
16735 }
16736
16737 // support: jQuery <1.8
16738 if ( !$.fn.addBack ) {
16739 $.fn.addBack = function( selector ) {
16740 return this.add( selector == null ?
16741 this.prevObject : this.prevObject.filter( selector )
16742 );
16743 };
16744 }
16745
16746 $.effects.animateClass = function( value, duration, easing, callback ) {
16747 var o = $.speed( duration, easing, callback );
16748
16749 return this.queue( function() {
16750 var animated = $( this ),
16751 baseClass = animated.attr( "class" ) || "",
16752 applyClassChange,
16753 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
16754
16755 // map the animated objects to store the original styles.
16756 allAnimations = allAnimations.map(function() {
16757 var el = $( this );
16758 return {
16759 el: el,
16760 start: getElementStyles( this )
16761 };
16762 });
16763
16764 // apply class change
16765 applyClassChange = function() {
16766 $.each( classAnimationActions, function(i, action) {
16767 if ( value[ action ] ) {
16768 animated[ action + "Class" ]( value[ action ] );
16769 }
16770 });
16771 };
16772 applyClassChange();
16773
16774 // map all animated objects again - calculate new styles and diff
16775 allAnimations = allAnimations.map(function() {
16776 this.end = getElementStyles( this.el[ 0 ] );
16777 this.diff = styleDifference( this.start, this.end );
16778 return this;
16779 });
16780
16781 // apply original class
16782 animated.attr( "class", baseClass );
16783
16784 // map all animated objects again - this time collecting a promise
16785 allAnimations = allAnimations.map(function() {
16786 var styleInfo = this,
16787 dfd = $.Deferred(),
16788 opts = $.extend({}, o, {
16789 queue: false,
16790 complete: function() {
16791 dfd.resolve( styleInfo );
16792 }
16793 });
16794
16795 this.el.animate( this.diff, opts );
16796 return dfd.promise();
16797 });
16798
16799 // once all animations have completed:
16800 $.when.apply( $, allAnimations.get() ).done(function() {
16801
16802 // set the final class
16803 applyClassChange();
16804
16805 // for each animated element,
16806 // clear all css properties that were animated
16807 $.each( arguments, function() {
16808 var el = this.el;
16809 $.each( this.diff, function(key) {
16810 el.css( key, "" );
16811 });
16812 });
16813
16814 // this is guarnteed to be there if you use jQuery.speed()
16815 // it also handles dequeuing the next anim...
16816 o.complete.call( animated[ 0 ] );
16817 });
16818 });
16819 };
16820
16821 $.fn.extend({
16822 addClass: (function( orig ) {
16823 return function( classNames, speed, easing, callback ) {
16824 return speed ?
16825 $.effects.animateClass.call( this,
16826 { add: classNames }, speed, easing, callback ) :
16827 orig.apply( this, arguments );
16828 };
16829 })( $.fn.addClass ),
16830
16831 removeClass: (function( orig ) {
16832 return function( classNames, speed, easing, callback ) {
16833 return arguments.length > 1 ?
16834 $.effects.animateClass.call( this,
16835 { remove: classNames }, speed, easing, callback ) :
16836 orig.apply( this, arguments );
16837 };
16838 })( $.fn.removeClass ),
16839
16840 toggleClass: (function( orig ) {
16841 return function( classNames, force, speed, easing, callback ) {
16842 if ( typeof force === "boolean" || force === undefined ) {
16843 if ( !speed ) {
16844 // without speed parameter
16845 return orig.apply( this, arguments );
16846 } else {
16847 return $.effects.animateClass.call( this,
16848 (force ? { add: classNames } : { remove: classNames }),
16849 speed, easing, callback );
16850 }
16851 } else {
16852 // without force parameter
16853 return $.effects.animateClass.call( this,
16854 { toggle: classNames }, force, speed, easing );
16855 }
16856 };
16857 })( $.fn.toggleClass ),
16858
16859 switchClass: function( remove, add, speed, easing, callback) {
16860 return $.effects.animateClass.call( this, {
16861 add: add,
16862 remove: remove
16863 }, speed, easing, callback );
16864 }
16865 });
16866
16867 })();
16868
16869 /******************************************************************************/
16870 /*********************************** EFFECTS **********************************/
16871 /******************************************************************************/
16872
16873 (function() {
16874
16875 $.extend( $.effects, {
16876 version: "1.10.3",
16877
16878 // Saves a set of properties in a data storage
16879 save: function( element, set ) {
16880 for( var i=0; i < set.length; i++ ) {
16881 if ( set[ i ] !== null ) {
16882 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
16883 }
16884 }
16885 },
16886
16887 // Restores a set of previously saved properties from a data storage
16888 restore: function( element, set ) {
16889 var val, i;
16890 for( i=0; i < set.length; i++ ) {
16891 if ( set[ i ] !== null ) {
16892 val = element.data( dataSpace + set[ i ] );
16893 // support: jQuery 1.6.2
16894 // http://bugs.jquery.com/ticket/9917
16895 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
16896 // We can't differentiate between "" and 0 here, so we just assume
16897 // empty string since it's likely to be a more common value...
16898 if ( val === undefined ) {
16899 val = "";
16900 }
16901 element.css( set[ i ], val );
16902 }
16903 }
16904 },
16905
16906 setMode: function( el, mode ) {
16907 if (mode === "toggle") {
16908 mode = el.is( ":hidden" ) ? "show" : "hide";
16909 }
16910 return mode;
16911 },
16912
16913 // Translates a [top,left] array into a baseline value
16914 // this should be a little more flexible in the future to handle a string & hash
16915 getBaseline: function( origin, original ) {
16916 var y, x;
16917 switch ( origin[ 0 ] ) {
16918 case "top": y = 0; break;
16919 case "middle": y = 0.5; break;
16920 case "bottom": y = 1; break;
16921 default: y = origin[ 0 ] / original.height;
16922 }
16923 switch ( origin[ 1 ] ) {
16924 case "left": x = 0; break;
16925 case "center": x = 0.5; break;
16926 case "right": x = 1; break;
16927 default: x = origin[ 1 ] / original.width;
16928 }
16929 return {
16930 x: x,
16931 y: y
16932 };
16933 },
16934
16935 // Wraps the element around a wrapper that copies position properties
16936 createWrapper: function( element ) {
16937
16938 // if the element is already wrapped, return it
16939 if ( element.parent().is( ".ui-effects-wrapper" )) {
16940 return element.parent();
16941 }
16942
16943 // wrap the element
16944 var props = {
16945 width: element.outerWidth(true),
16946 height: element.outerHeight(true),
16947 "float": element.css( "float" )
16948 },
16949 wrapper = $( "<div></div>" )
16950 .addClass( "ui-effects-wrapper" )
16951 .css({
16952 fontSize: "100%",
16953 background: "transparent",
16954 border: "none",
16955 margin: 0,
16956 padding: 0
16957 }),
16958 // Store the size in case width/height are defined in % - Fixes #5245
16959 size = {
16960 width: element.width(),
16961 height: element.height()
16962 },
16963 active = document.activeElement;
16964
16965 // support: Firefox
16966 // Firefox incorrectly exposes anonymous content
16967 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
16968 try {
16969 active.id;
16970 } catch( e ) {
16971 active = document.body;
16972 }
16973
16974 element.wrap( wrapper );
16975
16976 // Fixes #7595 - Elements lose focus when wrapped.
16977 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
16978 $( active ).focus();
16979 }
16980
16981 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
16982
16983 // transfer positioning properties to the wrapper
16984 if ( element.css( "position" ) === "static" ) {
16985 wrapper.css({ position: "relative" });
16986 element.css({ position: "relative" });
16987 } else {
16988 $.extend( props, {
16989 position: element.css( "position" ),
16990 zIndex: element.css( "z-index" )
16991 });
16992 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
16993 props[ pos ] = element.css( pos );
16994 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
16995 props[ pos ] = "auto";
16996 }
16997 });
16998 element.css({
16999 position: "relative",
17000 top: 0,
17001 left: 0,
17002 right: "auto",
17003 bottom: "auto"
17004 });
17005 }
17006 element.css(size);
17007
17008 return wrapper.css( props ).show();
17009 },
17010
17011 removeWrapper: function( element ) {
17012 var active = document.activeElement;
17013
17014 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
17015 element.parent().replaceWith( element );
17016
17017 // Fixes #7595 - Elements lose focus when wrapped.
17018 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
17019 $( active ).focus();
17020 }
17021 }
17022
17023
17024 return element;
17025 },
17026
17027 setTransition: function( element, list, factor, value ) {
17028 value = value || {};
17029 $.each( list, function( i, x ) {
17030 var unit = element.cssUnit( x );
17031 if ( unit[ 0 ] > 0 ) {
17032 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
17033 }
17034 });
17035 return value;
17036 }
17037 });
17038
17039 // return an effect options object for the given parameters:
17040 function _normalizeArguments( effect, options, speed, callback ) {
17041
17042 // allow passing all options as the first parameter
17043 if ( $.isPlainObject( effect ) ) {
17044 options = effect;
17045 effect = effect.effect;
17046 }
17047
17048 // convert to an object
17049 effect = { effect: effect };
17050
17051 // catch (effect, null, ...)
17052 if ( options == null ) {
17053 options = {};
17054 }
17055
17056 // catch (effect, callback)
17057 if ( $.isFunction( options ) ) {
17058 callback = options;
17059 speed = null;
17060 options = {};
17061 }
17062
17063 // catch (effect, speed, ?)
17064 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
17065 callback = speed;
17066 speed = options;
17067 options = {};
17068 }
17069
17070 // catch (effect, options, callback)
17071 if ( $.isFunction( speed ) ) {
17072 callback = speed;
17073 speed = null;
17074 }
17075
17076 // add options to effect
17077 if ( options ) {
17078 $.extend( effect, options );
17079 }
17080
17081 speed = speed || options.duration;
17082 effect.duration = $.fx.off ? 0 :
17083 typeof speed === "number" ? speed :
17084 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
17085 $.fx.speeds._default;
17086
17087 effect.complete = callback || options.complete;
17088
17089 return effect;
17090 }
17091
17092 function standardAnimationOption( option ) {
17093 // Valid standard speeds (nothing, number, named speed)
17094 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
17095 return true;
17096 }
17097
17098 // Invalid strings - treat as "normal" speed
17099 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
17100 return true;
17101 }
17102
17103 // Complete callback
17104 if ( $.isFunction( option ) ) {
17105 return true;
17106 }
17107
17108 // Options hash (but not naming an effect)
17109 if ( typeof option === "object" && !option.effect ) {
17110 return true;
17111 }
17112
17113 // Didn't match any standard API
17114 return false;
17115 }
17116
17117 $.fn.extend({
17118 effect: function( /* effect, options, speed, callback */ ) {
17119 var args = _normalizeArguments.apply( this, arguments ),
17120 mode = args.mode,
17121 queue = args.queue,
17122 effectMethod = $.effects.effect[ args.effect ];
17123
17124 if ( $.fx.off || !effectMethod ) {
17125 // delegate to the original method (e.g., .show()) if possible
17126 if ( mode ) {
17127 return this[ mode ]( args.duration, args.complete );
17128 } else {
17129 return this.each( function() {
17130 if ( args.complete ) {
17131 args.complete.call( this );
17132 }
17133 });
17134 }
17135 }
17136
17137 function run( next ) {
17138 var elem = $( this ),
17139 complete = args.complete,
17140 mode = args.mode;
17141
17142 function done() {
17143 if ( $.isFunction( complete ) ) {
17144 complete.call( elem[0] );
17145 }
17146 if ( $.isFunction( next ) ) {
17147 next();
17148 }
17149 }
17150
17151 // If the element already has the correct final state, delegate to
17152 // the core methods so the internal tracking of "olddisplay" works.
17153 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
17154 elem[ mode ]();
17155 done();
17156 } else {
17157 effectMethod.call( elem[0], args, done );
17158 }
17159 }
17160
17161 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
17162 },
17163
17164 show: (function( orig ) {
17165 return function( option ) {
17166 if ( standardAnimationOption( option ) ) {
17167 return orig.apply( this, arguments );
17168 } else {
17169 var args = _normalizeArguments.apply( this, arguments );
17170 args.mode = "show";
17171 return this.effect.call( this, args );
17172 }
17173 };
17174 })( $.fn.show ),
17175
17176 hide: (function( orig ) {
17177 return function( option ) {
17178 if ( standardAnimationOption( option ) ) {
17179 return orig.apply( this, arguments );
17180 } else {
17181 var args = _normalizeArguments.apply( this, arguments );
17182 args.mode = "hide";
17183 return this.effect.call( this, args );
17184 }
17185 };
17186 })( $.fn.hide ),
17187
17188 toggle: (function( orig ) {
17189 return function( option ) {
17190 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
17191 return orig.apply( this, arguments );
17192 } else {
17193 var args = _normalizeArguments.apply( this, arguments );
17194 args.mode = "toggle";
17195 return this.effect.call( this, args );
17196 }
17197 };
17198 })( $.fn.toggle ),
17199
17200 // helper functions
17201 cssUnit: function(key) {
17202 var style = this.css( key ),
17203 val = [];
17204
17205 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
17206 if ( style.indexOf( unit ) > 0 ) {
17207 val = [ parseFloat( style ), unit ];
17208 }
17209 });
17210 return val;
17211 }
17212 });
17213
17214 })();
17215
17216 /******************************************************************************/
17217 /*********************************** EASING ***********************************/
17218 /******************************************************************************/
17219
17220 (function() {
17221
17222 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
17223
17224 var baseEasings = {};
17225
17226 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
17227 baseEasings[ name ] = function( p ) {
17228 return Math.pow( p, i + 2 );
17229 };
17230 });
17231
17232 $.extend( baseEasings, {
17233 Sine: function ( p ) {
17234 return 1 - Math.cos( p * Math.PI / 2 );
17235 },
17236 Circ: function ( p ) {
17237 return 1 - Math.sqrt( 1 - p * p );
17238 },
17239 Elastic: function( p ) {
17240 return p === 0 || p === 1 ? p :
17241 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
17242 },
17243 Back: function( p ) {
17244 return p * p * ( 3 * p - 2 );
17245 },
17246 Bounce: function ( p ) {
17247 var pow2,
17248 bounce = 4;
17249
17250 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
17251 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
17252 }
17253 });
17254
17255 $.each( baseEasings, function( name, easeIn ) {
17256 $.easing[ "easeIn" + name ] = easeIn;
17257 $.easing[ "easeOut" + name ] = function( p ) {
17258 return 1 - easeIn( 1 - p );
17259 };
17260 $.easing[ "easeInOut" + name ] = function( p ) {
17261 return p < 0.5 ?
17262 easeIn( p * 2 ) / 2 :
17263 1 - easeIn( p * -2 + 2 ) / 2;
17264 };
17265 });
17266
17267 })();
17268
17269 })(jQuery);
17270 (function( $, undefined ) {
17271
17272 var rvertical = /up|down|vertical/,
17273 rpositivemotion = /up|left|vertical|horizontal/;
17274
17275 $.effects.effect.blind = function( o, done ) {
17276 // Create element
17277 var el = $( this ),
17278 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
17279 mode = $.effects.setMode( el, o.mode || "hide" ),
17280 direction = o.direction || "up",
17281 vertical = rvertical.test( direction ),
17282 ref = vertical ? "height" : "width",
17283 ref2 = vertical ? "top" : "left",
17284 motion = rpositivemotion.test( direction ),
17285 animation = {},
17286 show = mode === "show",
17287 wrapper, distance, margin;
17288
17289 // if already wrapped, the wrapper's properties are my property. #6245
17290 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
17291 $.effects.save( el.parent(), props );
17292 } else {
17293 $.effects.save( el, props );
17294 }
17295 el.show();
17296 wrapper = $.effects.createWrapper( el ).css({
17297 overflow: "hidden"
17298 });
17299
17300 distance = wrapper[ ref ]();
17301 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
17302
17303 animation[ ref ] = show ? distance : 0;
17304 if ( !motion ) {
17305 el
17306 .css( vertical ? "bottom" : "right", 0 )
17307 .css( vertical ? "top" : "left", "auto" )
17308 .css({ position: "absolute" });
17309
17310 animation[ ref2 ] = show ? margin : distance + margin;
17311 }
17312
17313 // start at 0 if we are showing
17314 if ( show ) {
17315 wrapper.css( ref, 0 );
17316 if ( ! motion ) {
17317 wrapper.css( ref2, margin + distance );
17318 }
17319 }
17320
17321 // Animate
17322 wrapper.animate( animation, {
17323 duration: o.duration,
17324 easing: o.easing,
17325 queue: false,
17326 complete: function() {
17327 if ( mode === "hide" ) {
17328 el.hide();
17329 }
17330 $.effects.restore( el, props );
17331 $.effects.removeWrapper( el );
17332 done();
17333 }
17334 });
17335
17336 };
17337
17338 })(jQuery);
17339 (function( $, undefined ) {
17340
17341 $.effects.effect.bounce = function( o, done ) {
17342 var el = $( this ),
17343 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
17344
17345 // defaults:
17346 mode = $.effects.setMode( el, o.mode || "effect" ),
17347 hide = mode === "hide",
17348 show = mode === "show",
17349 direction = o.direction || "up",
17350 distance = o.distance,
17351 times = o.times || 5,
17352
17353 // number of internal animations
17354 anims = times * 2 + ( show || hide ? 1 : 0 ),
17355 speed = o.duration / anims,
17356 easing = o.easing,
17357
17358 // utility:
17359 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
17360 motion = ( direction === "up" || direction === "left" ),
17361 i,
17362 upAnim,
17363 downAnim,
17364
17365 // we will need to re-assemble the queue to stack our animations in place
17366 queue = el.queue(),
17367 queuelen = queue.length;
17368
17369 // Avoid touching opacity to prevent clearType and PNG issues in IE
17370 if ( show || hide ) {
17371 props.push( "opacity" );
17372 }
17373
17374 $.effects.save( el, props );
17375 el.show();
17376 $.effects.createWrapper( el ); // Create Wrapper
17377
17378 // default distance for the BIGGEST bounce is the outer Distance / 3
17379 if ( !distance ) {
17380 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
17381 }
17382
17383 if ( show ) {
17384 downAnim = { opacity: 1 };
17385 downAnim[ ref ] = 0;
17386
17387 // if we are showing, force opacity 0 and set the initial position
17388 // then do the "first" animation
17389 el.css( "opacity", 0 )
17390 .css( ref, motion ? -distance * 2 : distance * 2 )
17391 .animate( downAnim, speed, easing );
17392 }
17393
17394 // start at the smallest distance if we are hiding
17395 if ( hide ) {
17396 distance = distance / Math.pow( 2, times - 1 );
17397 }
17398
17399 downAnim = {};
17400 downAnim[ ref ] = 0;
17401 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
17402 for ( i = 0; i < times; i++ ) {
17403 upAnim = {};
17404 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
17405
17406 el.animate( upAnim, speed, easing )
17407 .animate( downAnim, speed, easing );
17408
17409 distance = hide ? distance * 2 : distance / 2;
17410 }
17411
17412 // Last Bounce when Hiding
17413 if ( hide ) {
17414 upAnim = { opacity: 0 };
17415 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
17416
17417 el.animate( upAnim, speed, easing );
17418 }
17419
17420 el.queue(function() {
17421 if ( hide ) {
17422 el.hide();
17423 }
17424 $.effects.restore( el, props );
17425 $.effects.removeWrapper( el );
17426 done();
17427 });
17428
17429 // inject all the animations we just queued to be first in line (after "inprogress")
17430 if ( queuelen > 1) {
17431 queue.splice.apply( queue,
17432 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
17433 }
17434 el.dequeue();
17435
17436 };
17437
17438 })(jQuery);
17439 (function( $, undefined ) {
17440
17441 $.effects.effect.clip = function( o, done ) {
17442 // Create element
17443 var el = $( this ),
17444 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
17445 mode = $.effects.setMode( el, o.mode || "hide" ),
17446 show = mode === "show",
17447 direction = o.direction || "vertical",
17448 vert = direction === "vertical",
17449 size = vert ? "height" : "width",
17450 position = vert ? "top" : "left",
17451 animation = {},
17452 wrapper, animate, distance;
17453
17454 // Save & Show
17455 $.effects.save( el, props );
17456 el.show();
17457
17458 // Create Wrapper
17459 wrapper = $.effects.createWrapper( el ).css({
17460 overflow: "hidden"
17461 });
17462 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
17463 distance = animate[ size ]();
17464
17465 // Shift
17466 if ( show ) {
17467 animate.css( size, 0 );
17468 animate.css( position, distance / 2 );
17469 }
17470
17471 // Create Animation Object:
17472 animation[ size ] = show ? distance : 0;
17473 animation[ position ] = show ? 0 : distance / 2;
17474
17475 // Animate
17476 animate.animate( animation, {
17477 queue: false,
17478 duration: o.duration,
17479 easing: o.easing,
17480 complete: function() {
17481 if ( !show ) {
17482 el.hide();
17483 }
17484 $.effects.restore( el, props );
17485 $.effects.removeWrapper( el );
17486 done();
17487 }
17488 });
17489
17490 };
17491
17492 })(jQuery);
17493 (function( $, undefined ) {
17494
17495 $.effects.effect.drop = function( o, done ) {
17496
17497 var el = $( this ),
17498 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
17499 mode = $.effects.setMode( el, o.mode || "hide" ),
17500 show = mode === "show",
17501 direction = o.direction || "left",
17502 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
17503 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
17504 animation = {
17505 opacity: show ? 1 : 0
17506 },
17507 distance;
17508
17509 // Adjust
17510 $.effects.save( el, props );
17511 el.show();
17512 $.effects.createWrapper( el );
17513
17514 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
17515
17516 if ( show ) {
17517 el
17518 .css( "opacity", 0 )
17519 .css( ref, motion === "pos" ? -distance : distance );
17520 }
17521
17522 // Animation
17523 animation[ ref ] = ( show ?
17524 ( motion === "pos" ? "+=" : "-=" ) :
17525 ( motion === "pos" ? "-=" : "+=" ) ) +
17526 distance;
17527
17528 // Animate
17529 el.animate( animation, {
17530 queue: false,
17531 duration: o.duration,
17532 easing: o.easing,
17533 complete: function() {
17534 if ( mode === "hide" ) {
17535 el.hide();
17536 }
17537 $.effects.restore( el, props );
17538 $.effects.removeWrapper( el );
17539 done();
17540 }
17541 });
17542 };
17543
17544 })(jQuery);
17545 (function( $, undefined ) {
17546
17547 $.effects.effect.explode = function( o, done ) {
17548
17549 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
17550 cells = rows,
17551 el = $( this ),
17552 mode = $.effects.setMode( el, o.mode || "hide" ),
17553 show = mode === "show",
17554
17555 // show and then visibility:hidden the element before calculating offset
17556 offset = el.show().css( "visibility", "hidden" ).offset(),
17557
17558 // width and height of a piece
17559 width = Math.ceil( el.outerWidth() / cells ),
17560 height = Math.ceil( el.outerHeight() / rows ),
17561 pieces = [],
17562
17563 // loop
17564 i, j, left, top, mx, my;
17565
17566 // children animate complete:
17567 function childComplete() {
17568 pieces.push( this );
17569 if ( pieces.length === rows * cells ) {
17570 animComplete();
17571 }
17572 }
17573
17574 // clone the element for each row and cell.
17575 for( i = 0; i < rows ; i++ ) { // ===>
17576 top = offset.top + i * height;
17577 my = i - ( rows - 1 ) / 2 ;
17578
17579 for( j = 0; j < cells ; j++ ) { // |||
17580 left = offset.left + j * width;
17581 mx = j - ( cells - 1 ) / 2 ;
17582
17583 // Create a clone of the now hidden main element that will be absolute positioned
17584 // within a wrapper div off the -left and -top equal to size of our pieces
17585 el
17586 .clone()
17587 .appendTo( "body" )
17588 .wrap( "<div></div>" )
17589 .css({
17590 position: "absolute",
17591 visibility: "visible",
17592 left: -j * width,
17593 top: -i * height
17594 })
17595
17596 // select the wrapper - make it overflow: hidden and absolute positioned based on
17597 // where the original was located +left and +top equal to the size of pieces
17598 .parent()
17599 .addClass( "ui-effects-explode" )
17600 .css({
17601 position: "absolute",
17602 overflow: "hidden",
17603 width: width,
17604 height: height,
17605 left: left + ( show ? mx * width : 0 ),
17606 top: top + ( show ? my * height : 0 ),
17607 opacity: show ? 0 : 1
17608 }).animate({
17609 left: left + ( show ? 0 : mx * width ),
17610 top: top + ( show ? 0 : my * height ),
17611 opacity: show ? 1 : 0
17612 }, o.duration || 500, o.easing, childComplete );
17613 }
17614 }
17615
17616 function animComplete() {
17617 el.css({
17618 visibility: "visible"
17619 });
17620 $( pieces ).remove();
17621 if ( !show ) {
17622 el.hide();
17623 }
17624 done();
17625 }
17626 };
17627
17628 })(jQuery);
17629 (function( $, undefined ) {
17630
17631 $.effects.effect.fade = function( o, done ) {
17632 var el = $( this ),
17633 mode = $.effects.setMode( el, o.mode || "toggle" );
17634
17635 el.animate({
17636 opacity: mode
17637 }, {
17638 queue: false,
17639 duration: o.duration,
17640 easing: o.easing,
17641 complete: done
17642 });
17643 };
17644
17645 })( jQuery );
17646 (function( $, undefined ) {
17647
17648 $.effects.effect.fold = function( o, done ) {
17649
17650 // Create element
17651 var el = $( this ),
17652 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
17653 mode = $.effects.setMode( el, o.mode || "hide" ),
17654 show = mode === "show",
17655 hide = mode === "hide",
17656 size = o.size || 15,
17657 percent = /([0-9]+)%/.exec( size ),
17658 horizFirst = !!o.horizFirst,
17659 widthFirst = show !== horizFirst,
17660 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
17661 duration = o.duration / 2,
17662 wrapper, distance,
17663 animation1 = {},
17664 animation2 = {};
17665
17666 $.effects.save( el, props );
17667 el.show();
17668
17669 // Create Wrapper
17670 wrapper = $.effects.createWrapper( el ).css({
17671 overflow: "hidden"
17672 });
17673 distance = widthFirst ?
17674 [ wrapper.width(), wrapper.height() ] :
17675 [ wrapper.height(), wrapper.width() ];
17676
17677 if ( percent ) {
17678 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
17679 }
17680 if ( show ) {
17681 wrapper.css( horizFirst ? {
17682 height: 0,
17683 width: size
17684 } : {
17685 height: size,
17686 width: 0
17687 });
17688 }
17689
17690 // Animation
17691 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
17692 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
17693
17694 // Animate
17695 wrapper
17696 .animate( animation1, duration, o.easing )
17697 .animate( animation2, duration, o.easing, function() {
17698 if ( hide ) {
17699 el.hide();
17700 }
17701 $.effects.restore( el, props );
17702 $.effects.removeWrapper( el );
17703 done();
17704 });
17705
17706 };
17707
17708 })(jQuery);
17709 (function( $, undefined ) {
17710
17711 $.effects.effect.highlight = function( o, done ) {
17712 var elem = $( this ),
17713 props = [ "backgroundImage", "backgroundColor", "opacity" ],
17714 mode = $.effects.setMode( elem, o.mode || "show" ),
17715 animation = {
17716 backgroundColor: elem.css( "backgroundColor" )
17717 };
17718
17719 if (mode === "hide") {
17720 animation.opacity = 0;
17721 }
17722
17723 $.effects.save( elem, props );
17724
17725 elem
17726 .show()
17727 .css({
17728 backgroundImage: "none",
17729 backgroundColor: o.color || "#ffff99"
17730 })
17731 .animate( animation, {
17732 queue: false,
17733 duration: o.duration,
17734 easing: o.easing,
17735 complete: function() {
17736 if ( mode === "hide" ) {
17737 elem.hide();
17738 }
17739 $.effects.restore( elem, props );
17740 done();
17741 }
17742 });
17743 };
17744
17745 })(jQuery);
17746 (function( $, undefined ) {
17747
17748 $.effects.effect.pulsate = function( o, done ) {
17749 var elem = $( this ),
17750 mode = $.effects.setMode( elem, o.mode || "show" ),
17751 show = mode === "show",
17752 hide = mode === "hide",
17753 showhide = ( show || mode === "hide" ),
17754
17755 // showing or hiding leaves of the "last" animation
17756 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
17757 duration = o.duration / anims,
17758 animateTo = 0,
17759 queue = elem.queue(),
17760 queuelen = queue.length,
17761 i;
17762
17763 if ( show || !elem.is(":visible")) {
17764 elem.css( "opacity", 0 ).show();
17765 animateTo = 1;
17766 }
17767
17768 // anims - 1 opacity "toggles"
17769 for ( i = 1; i < anims; i++ ) {
17770 elem.animate({
17771 opacity: animateTo
17772 }, duration, o.easing );
17773 animateTo = 1 - animateTo;
17774 }
17775
17776 elem.animate({
17777 opacity: animateTo
17778 }, duration, o.easing);
17779
17780 elem.queue(function() {
17781 if ( hide ) {
17782 elem.hide();
17783 }
17784 done();
17785 });
17786
17787 // We just queued up "anims" animations, we need to put them next in the queue
17788 if ( queuelen > 1 ) {
17789 queue.splice.apply( queue,
17790 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
17791 }
17792 elem.dequeue();
17793 };
17794
17795 })(jQuery);
17796 (function( $, undefined ) {
17797
17798 $.effects.effect.puff = function( o, done ) {
17799 var elem = $( this ),
17800 mode = $.effects.setMode( elem, o.mode || "hide" ),
17801 hide = mode === "hide",
17802 percent = parseInt( o.percent, 10 ) || 150,
17803 factor = percent / 100,
17804 original = {
17805 height: elem.height(),
17806 width: elem.width(),
17807 outerHeight: elem.outerHeight(),
17808 outerWidth: elem.outerWidth()
17809 };
17810
17811 $.extend( o, {
17812 effect: "scale",
17813 queue: false,
17814 fade: true,
17815 mode: mode,
17816 complete: done,
17817 percent: hide ? percent : 100,
17818 from: hide ?
17819 original :
17820 {
17821 height: original.height * factor,
17822 width: original.width * factor,
17823 outerHeight: original.outerHeight * factor,
17824 outerWidth: original.outerWidth * factor
17825 }
17826 });
17827
17828 elem.effect( o );
17829 };
17830
17831 $.effects.effect.scale = function( o, done ) {
17832
17833 // Create element
17834 var el = $( this ),
17835 options = $.extend( true, {}, o ),
17836 mode = $.effects.setMode( el, o.mode || "effect" ),
17837 percent = parseInt( o.percent, 10 ) ||
17838 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
17839 direction = o.direction || "both",
17840 origin = o.origin,
17841 original = {
17842 height: el.height(),
17843 width: el.width(),
17844 outerHeight: el.outerHeight(),
17845 outerWidth: el.outerWidth()
17846 },
17847 factor = {
17848 y: direction !== "horizontal" ? (percent / 100) : 1,
17849 x: direction !== "vertical" ? (percent / 100) : 1
17850 };
17851
17852 // We are going to pass this effect to the size effect:
17853 options.effect = "size";
17854 options.queue = false;
17855 options.complete = done;
17856
17857 // Set default origin and restore for show/hide
17858 if ( mode !== "effect" ) {
17859 options.origin = origin || ["middle","center"];
17860 options.restore = true;
17861 }
17862
17863 options.from = o.from || ( mode === "show" ? {
17864 height: 0,
17865 width: 0,
17866 outerHeight: 0,
17867 outerWidth: 0
17868 } : original );
17869 options.to = {
17870 height: original.height * factor.y,
17871 width: original.width * factor.x,
17872 outerHeight: original.outerHeight * factor.y,
17873 outerWidth: original.outerWidth * factor.x
17874 };
17875
17876 // Fade option to support puff
17877 if ( options.fade ) {
17878 if ( mode === "show" ) {
17879 options.from.opacity = 0;
17880 options.to.opacity = 1;
17881 }
17882 if ( mode === "hide" ) {
17883 options.from.opacity = 1;
17884 options.to.opacity = 0;
17885 }
17886 }
17887
17888 // Animate
17889 el.effect( options );
17890
17891 };
17892
17893 $.effects.effect.size = function( o, done ) {
17894
17895 // Create element
17896 var original, baseline, factor,
17897 el = $( this ),
17898 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
17899
17900 // Always restore
17901 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
17902
17903 // Copy for children
17904 props2 = [ "width", "height", "overflow" ],
17905 cProps = [ "fontSize" ],
17906 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
17907 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
17908
17909 // Set options
17910 mode = $.effects.setMode( el, o.mode || "effect" ),
17911 restore = o.restore || mode !== "effect",
17912 scale = o.scale || "both",
17913 origin = o.origin || [ "middle", "center" ],
17914 position = el.css( "position" ),
17915 props = restore ? props0 : props1,
17916 zero = {
17917 height: 0,
17918 width: 0,
17919 outerHeight: 0,
17920 outerWidth: 0
17921 };
17922
17923 if ( mode === "show" ) {
17924 el.show();
17925 }
17926 original = {
17927 height: el.height(),
17928 width: el.width(),
17929 outerHeight: el.outerHeight(),
17930 outerWidth: el.outerWidth()
17931 };
17932
17933 if ( o.mode === "toggle" && mode === "show" ) {
17934 el.from = o.to || zero;
17935 el.to = o.from || original;
17936 } else {
17937 el.from = o.from || ( mode === "show" ? zero : original );
17938 el.to = o.to || ( mode === "hide" ? zero : original );
17939 }
17940
17941 // Set scaling factor
17942 factor = {
17943 from: {
17944 y: el.from.height / original.height,
17945 x: el.from.width / original.width
17946 },
17947 to: {
17948 y: el.to.height / original.height,
17949 x: el.to.width / original.width
17950 }
17951 };
17952
17953 // Scale the css box
17954 if ( scale === "box" || scale === "both" ) {
17955
17956 // Vertical props scaling
17957 if ( factor.from.y !== factor.to.y ) {
17958 props = props.concat( vProps );
17959 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
17960 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
17961 }
17962
17963 // Horizontal props scaling
17964 if ( factor.from.x !== factor.to.x ) {
17965 props = props.concat( hProps );
17966 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
17967 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
17968 }
17969 }
17970
17971 // Scale the content
17972 if ( scale === "content" || scale === "both" ) {
17973
17974 // Vertical props scaling
17975 if ( factor.from.y !== factor.to.y ) {
17976 props = props.concat( cProps ).concat( props2 );
17977 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
17978 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
17979 }
17980 }
17981
17982 $.effects.save( el, props );
17983 el.show();
17984 $.effects.createWrapper( el );
17985 el.css( "overflow", "hidden" ).css( el.from );
17986
17987 // Adjust
17988 if (origin) { // Calculate baseline shifts
17989 baseline = $.effects.getBaseline( origin, original );
17990 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
17991 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
17992 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
17993 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
17994 }
17995 el.css( el.from ); // set top & left
17996
17997 // Animate
17998 if ( scale === "content" || scale === "both" ) { // Scale the children
17999
18000 // Add margins/font-size
18001 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
18002 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
18003 props2 = props0.concat(vProps).concat(hProps);
18004
18005 el.find( "*[width]" ).each( function(){
18006 var child = $( this ),
18007 c_original = {
18008 height: child.height(),
18009 width: child.width(),
18010 outerHeight: child.outerHeight(),
18011 outerWidth: child.outerWidth()
18012 };
18013 if (restore) {
18014 $.effects.save(child, props2);
18015 }
18016
18017 child.from = {
18018 height: c_original.height * factor.from.y,
18019 width: c_original.width * factor.from.x,
18020 outerHeight: c_original.outerHeight * factor.from.y,
18021 outerWidth: c_original.outerWidth * factor.from.x
18022 };
18023 child.to = {
18024 height: c_original.height * factor.to.y,
18025 width: c_original.width * factor.to.x,
18026 outerHeight: c_original.height * factor.to.y,
18027 outerWidth: c_original.width * factor.to.x
18028 };
18029
18030 // Vertical props scaling
18031 if ( factor.from.y !== factor.to.y ) {
18032 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
18033 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
18034 }
18035
18036 // Horizontal props scaling
18037 if ( factor.from.x !== factor.to.x ) {
18038 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
18039 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
18040 }
18041
18042 // Animate children
18043 child.css( child.from );
18044 child.animate( child.to, o.duration, o.easing, function() {
18045
18046 // Restore children
18047 if ( restore ) {
18048 $.effects.restore( child, props2 );
18049 }
18050 });
18051 });
18052 }
18053
18054 // Animate
18055 el.animate( el.to, {
18056 queue: false,
18057 duration: o.duration,
18058 easing: o.easing,
18059 complete: function() {
18060 if ( el.to.opacity === 0 ) {
18061 el.css( "opacity", el.from.opacity );
18062 }
18063 if( mode === "hide" ) {
18064 el.hide();
18065 }
18066 $.effects.restore( el, props );
18067 if ( !restore ) {
18068
18069 // we need to calculate our new positioning based on the scaling
18070 if ( position === "static" ) {
18071 el.css({
18072 position: "relative",
18073 top: el.to.top,
18074 left: el.to.left
18075 });
18076 } else {
18077 $.each([ "top", "left" ], function( idx, pos ) {
18078 el.css( pos, function( _, str ) {
18079 var val = parseInt( str, 10 ),
18080 toRef = idx ? el.to.left : el.to.top;
18081
18082 // if original was "auto", recalculate the new value from wrapper
18083 if ( str === "auto" ) {
18084 return toRef + "px";
18085 }
18086
18087 return val + toRef + "px";
18088 });
18089 });
18090 }
18091 }
18092
18093 $.effects.removeWrapper( el );
18094 done();
18095 }
18096 });
18097
18098 };
18099
18100 })(jQuery);
18101 (function( $, undefined ) {
18102
18103 $.effects.effect.shake = function( o, done ) {
18104
18105 var el = $( this ),
18106 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
18107 mode = $.effects.setMode( el, o.mode || "effect" ),
18108 direction = o.direction || "left",
18109 distance = o.distance || 20,
18110 times = o.times || 3,
18111 anims = times * 2 + 1,
18112 speed = Math.round(o.duration/anims),
18113 ref = (direction === "up" || direction === "down") ? "top" : "left",
18114 positiveMotion = (direction === "up" || direction === "left"),
18115 animation = {},
18116 animation1 = {},
18117 animation2 = {},
18118 i,
18119
18120 // we will need to re-assemble the queue to stack our animations in place
18121 queue = el.queue(),
18122 queuelen = queue.length;
18123
18124 $.effects.save( el, props );
18125 el.show();
18126 $.effects.createWrapper( el );
18127
18128 // Animation
18129 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
18130 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
18131 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
18132
18133 // Animate
18134 el.animate( animation, speed, o.easing );
18135
18136 // Shakes
18137 for ( i = 1; i < times; i++ ) {
18138 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
18139 }
18140 el
18141 .animate( animation1, speed, o.easing )
18142 .animate( animation, speed / 2, o.easing )
18143 .queue(function() {
18144 if ( mode === "hide" ) {
18145 el.hide();
18146 }
18147 $.effects.restore( el, props );
18148 $.effects.removeWrapper( el );
18149 done();
18150 });
18151
18152 // inject all the animations we just queued to be first in line (after "inprogress")
18153 if ( queuelen > 1) {
18154 queue.splice.apply( queue,
18155 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
18156 }
18157 el.dequeue();
18158
18159 };
18160
18161 })(jQuery);
18162 (function( $, undefined ) {
18163
18164 $.effects.effect.slide = function( o, done ) {
18165
18166 // Create element
18167 var el = $( this ),
18168 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
18169 mode = $.effects.setMode( el, o.mode || "show" ),
18170 show = mode === "show",
18171 direction = o.direction || "left",
18172 ref = (direction === "up" || direction === "down") ? "top" : "left",
18173 positiveMotion = (direction === "up" || direction === "left"),
18174 distance,
18175 animation = {};
18176
18177 // Adjust
18178 $.effects.save( el, props );
18179 el.show();
18180 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
18181
18182 $.effects.createWrapper( el ).css({
18183 overflow: "hidden"
18184 });
18185
18186 if ( show ) {
18187 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
18188 }
18189
18190 // Animation
18191 animation[ ref ] = ( show ?
18192 ( positiveMotion ? "+=" : "-=") :
18193 ( positiveMotion ? "-=" : "+=")) +
18194 distance;
18195
18196 // Animate
18197 el.animate( animation, {
18198 queue: false,
18199 duration: o.duration,
18200 easing: o.easing,
18201 complete: function() {
18202 if ( mode === "hide" ) {
18203 el.hide();
18204 }
18205 $.effects.restore( el, props );
18206 $.effects.removeWrapper( el );
18207 done();
18208 }
18209 });
18210 };
18211
18212 })(jQuery);
18213 (function( $, undefined ) {
18214
18215 $.effects.effect.transfer = function( o, done ) {
18216 var elem = $( this ),
18217 target = $( o.to ),
18218 targetFixed = target.css( "position" ) === "fixed",
18219 body = $("body"),
18220 fixTop = targetFixed ? body.scrollTop() : 0,
18221 fixLeft = targetFixed ? body.scrollLeft() : 0,
18222 endPosition = target.offset(),
18223 animation = {
18224 top: endPosition.top - fixTop ,
18225 left: endPosition.left - fixLeft ,
18226 height: target.innerHeight(),
18227 width: target.innerWidth()
18228 },
18229 startPosition = elem.offset(),
18230 transfer = $( "<div class='ui-effects-transfer'></div>" )
18231 .appendTo( document.body )
18232 .addClass( o.className )
18233 .css({
18234 top: startPosition.top - fixTop ,
18235 left: startPosition.left - fixLeft ,
18236 height: elem.innerHeight(),
18237 width: elem.innerWidth(),
18238 position: targetFixed ? "fixed" : "absolute"
18239 })
18240 .animate( animation, o.duration, o.easing, function() {
18241 transfer.remove();
18242 done();
18243 });
18244 };
18245
18246 })(jQuery);
18247 /**
18248
18249 JSZip - A Javascript class for generating and reading zip files
18250 <http://stuartk.com/jszip>
18251
18252 (c) 2009-2012 Stuart Knightley <stuart [at] stuartk.com>
18253 Dual licenced under the MIT license or GPLv3. See LICENSE.markdown.
18254
18255 Usage:
18256 zip = new JSZip();
18257 zip.file("hello.txt", "Hello, World!").add("tempfile", "nothing");
18258 zip.folder("images").file("smile.gif", base64Data, {base64: true});
18259 zip.file("Xmas.txt", "Ho ho ho !", {date : new Date("December 25, 2007 00:00:01")});
18260 zip.remove("tempfile");
18261
18262 base64zip = zip.generate();
18263
18264 **/
18265
18266 /**
18267 * Representation a of zip file in js
18268 * @constructor
18269 * @param {String=|ArrayBuffer=|Uint8Array=} data the data to load, if any (optional).
18270 * @param {Object=} options the options for creating this objects (optional).
18271 */
18272 var JSZip = function(data, options) {
18273 // object containing the files :
18274 // {
18275 // "folder/" : {...},
18276 // "folder/data.txt" : {...}
18277 // }
18278 this.files = {};
18279
18280 // Where we are in the hierarchy
18281 this.root = "";
18282
18283 if (data) {
18284 this.load(data, options);
18285 }
18286 };
18287
18288 JSZip.signature = {
18289 LOCAL_FILE_HEADER : "\x50\x4b\x03\x04",
18290 CENTRAL_FILE_HEADER : "\x50\x4b\x01\x02",
18291 CENTRAL_DIRECTORY_END : "\x50\x4b\x05\x06",
18292 ZIP64_CENTRAL_DIRECTORY_LOCATOR : "\x50\x4b\x06\x07",
18293 ZIP64_CENTRAL_DIRECTORY_END : "\x50\x4b\x06\x06",
18294 DATA_DESCRIPTOR : "\x50\x4b\x07\x08"
18295 };
18296
18297 // Default properties for a new file
18298 JSZip.defaults = {
18299 base64: false,
18300 binary: false,
18301 dir: false,
18302 date: null
18303 };
18304
18305
18306 JSZip.prototype = (function () {
18307 /**
18308 * A simple object representing a file in the zip file.
18309 * @constructor
18310 * @param {string} name the name of the file
18311 * @param {string} data the data
18312 * @param {Object} options the options of the file
18313 */
18314 var ZipObject = function (name, data, options) {
18315 this.name = name;
18316 this.data = data;
18317 this.options = options;
18318 };
18319
18320 ZipObject.prototype = {
18321 /**
18322 * Return the content as UTF8 string.
18323 * @return {string} the UTF8 string.
18324 */
18325 asText : function () {
18326 var result = this.data;
18327 if (result === null || typeof result === "undefined") {
18328 return "";
18329 }
18330 if (this.options.base64) {
18331 result = JSZipBase64.decode(result);
18332 }
18333 if (this.options.binary) {
18334 result = JSZip.prototype.utf8decode(result);
18335 }
18336 return result;
18337 },
18338 /**
18339 * Returns the binary content.
18340 * @return {string} the content as binary.
18341 */
18342 asBinary : function () {
18343 var result = this.data;
18344 if (result === null || typeof result === "undefined") {
18345 return "";
18346 }
18347 if (this.options.base64) {
18348 result = JSZipBase64.decode(result);
18349 }
18350 if (!this.options.binary) {
18351 result = JSZip.prototype.utf8encode(result);
18352 }
18353 return result;
18354 },
18355 /**
18356 * Returns the content as an Uint8Array.
18357 * @return {Uint8Array} the content as an Uint8Array.
18358 */
18359 asUint8Array : function () {
18360 return JSZip.utils.string2Uint8Array(this.asBinary());
18361 },
18362 /**
18363 * Returns the content as an ArrayBuffer.
18364 * @return {ArrayBuffer} the content as an ArrayBufer.
18365 */
18366 asArrayBuffer : function () {
18367 return JSZip.utils.string2Uint8Array(this.asBinary()).buffer;
18368 }
18369 };
18370
18371 /**
18372 * Transform an integer into a string in hexadecimal.
18373 * @private
18374 * @param {number} dec the number to convert.
18375 * @param {number} bytes the number of bytes to generate.
18376 * @returns {string} the result.
18377 */
18378 var decToHex = function(dec, bytes) {
18379 var hex = "", i;
18380 for(i = 0; i < bytes; i++) {
18381 hex += String.fromCharCode(dec&0xff);
18382 dec=dec>>>8;
18383 }
18384 return hex;
18385 };
18386
18387 /**
18388 * Merge the objects passed as parameters into a new one.
18389 * @private
18390 * @param {...Object} var_args All objects to merge.
18391 * @return {Object} a new object with the data of the others.
18392 */
18393 var extend = function () {
18394 var result = {}, i, attr;
18395 for (i = 0; i < arguments.length; i++) { // arguments is not enumerable in some browsers
18396 for (attr in arguments[i]) {
18397 if (arguments[i].hasOwnProperty(attr) && typeof result[attr] === "undefined") {
18398 result[attr] = arguments[i][attr];
18399 }
18400 }
18401 }
18402 return result;
18403 };
18404
18405 /**
18406 * Transforms the (incomplete) options from the user into the complete
18407 * set of options to create a file.
18408 * @private
18409 * @param {Object} o the options from the user.
18410 * @return {Object} the complete set of options.
18411 */
18412 var prepareFileAttrs = function (o) {
18413 o = o || {};
18414 if (o.base64 === true && o.binary == null) {
18415 o.binary = true;
18416 }
18417 o = extend(o, JSZip.defaults);
18418 o.date = o.date || new Date();
18419
18420 return o;
18421 };
18422
18423 /**
18424 * Add a file in the current folder.
18425 * @private
18426 * @param {string} name the name of the file
18427 * @param {String|ArrayBuffer|Uint8Array} data the data of the file
18428 * @param {Object} o the options of the file
18429 * @return {Object} the new file.
18430 */
18431 var fileAdd = function (name, data, o) {
18432 // be sure sub folders exist
18433 var parent = parentFolder(name);
18434 if (parent) {
18435 folderAdd.call(this, parent);
18436 }
18437
18438 o = prepareFileAttrs(o);
18439
18440 if (o.dir || data === null || typeof data === "undefined") {
18441 o.base64 = false;
18442 o.binary = false;
18443 data = null;
18444 } else if (JSZip.support.uint8array && data instanceof Uint8Array) {
18445 o.base64 = false;
18446 o.binary = true;
18447 data = JSZip.utils.uint8Array2String(data);
18448 } else if (JSZip.support.arraybuffer && data instanceof ArrayBuffer) {
18449 o.base64 = false;
18450 o.binary = true;
18451 var bufferView = new Uint8Array(data);
18452 data = JSZip.utils.uint8Array2String(bufferView);
18453 } else if (o.binary && !o.base64) {
18454 // optimizedBinaryString == true means that the file has already been filtered with a 0xFF mask
18455 if (o.optimizedBinaryString !== true) {
18456 // this is a string, not in a base64 format.
18457 // Be sure that this is a correct "binary string"
18458 data = JSZip.utils.string2binary(data);
18459 }
18460 // we remove this option since it's only relevant here
18461 delete o.optimizedBinaryString;
18462 }
18463
18464 return this.files[name] = new ZipObject(name, data, o);
18465 };
18466
18467
18468 /**
18469 * Find the parent folder of the path.
18470 * @private
18471 * @param {string} path the path to use
18472 * @return {string} the parent folder, or ""
18473 */
18474 var parentFolder = function (path) {
18475 if (path.slice(-1) == '/') {
18476 path = path.substring(0, path.length - 1);
18477 }
18478 var lastSlash = path.lastIndexOf('/');
18479 return (lastSlash > 0) ? path.substring(0, lastSlash) : "";
18480 };
18481
18482 /**
18483 * Add a (sub) folder in the current folder.
18484 * @private
18485 * @param {string} name the folder's name
18486 * @return {Object} the new folder.
18487 */
18488 var folderAdd = function (name) {
18489 // Check the name ends with a /
18490 if (name.slice(-1) != "/") {
18491 name += "/"; // IE doesn't like substr(-1)
18492 }
18493
18494 // Does this folder already exist?
18495 if (!this.files[name]) {
18496 // be sure sub folders exist
18497 var parent = parentFolder(name);
18498 if (parent) {
18499 folderAdd.call(this, parent);
18500 }
18501
18502 fileAdd.call(this, name, null, {dir:true});
18503 }
18504 return this.files[name];
18505 };
18506
18507 /**
18508 * Generate the data found in the local header of a zip file.
18509 * Do not create it now, as some parts are re-used later.
18510 * @private
18511 * @param {Object} file the file to use.
18512 * @param {string} utfEncodedFileName the file name, utf8 encoded.
18513 * @param {string} compressionType the compression to use.
18514 * @return {Object} an object containing header and compressedData.
18515 */
18516 var prepareLocalHeaderData = function(file, utfEncodedFileName, compressionType) {
18517 var useUTF8 = utfEncodedFileName !== file.name,
18518 data = file.asBinary(),
18519 o = file.options,
18520 dosTime,
18521 dosDate;
18522
18523 // date
18524 // @see http://www.delorie.com/djgpp/doc/rbinter/it/52/13.html
18525 // @see http://www.delorie.com/djgpp/doc/rbinter/it/65/16.html
18526 // @see http://www.delorie.com/djgpp/doc/rbinter/it/66/16.html
18527
18528 dosTime = o.date.getHours();
18529 dosTime = dosTime << 6;
18530 dosTime = dosTime | o.date.getMinutes();
18531 dosTime = dosTime << 5;
18532 dosTime = dosTime | o.date.getSeconds() / 2;
18533
18534 dosDate = o.date.getFullYear() - 1980;
18535 dosDate = dosDate << 4;
18536 dosDate = dosDate | (o.date.getMonth() + 1);
18537 dosDate = dosDate << 5;
18538 dosDate = dosDate | o.date.getDate();
18539
18540 var hasData = data !== null && data.length !== 0;
18541
18542 var compression = JSZip.compressions[compressionType];
18543 var compressedData = hasData ? compression.compress(data) : '';
18544
18545 var header = "";
18546
18547 // version needed to extract
18548 header += "\x0A\x00";
18549 // general purpose bit flag
18550 // set bit 11 if utf8
18551 header += useUTF8 ? "\x00\x08" : "\x00\x00";
18552 // compression method
18553 header += hasData ? compression.magic : JSZip.compressions['STORE'].magic;
18554 // last mod file time
18555 header += decToHex(dosTime, 2);
18556 // last mod file date
18557 header += decToHex(dosDate, 2);
18558 // crc-32
18559 header += hasData ? decToHex(this.crc32(data), 4) : '\x00\x00\x00\x00';
18560 // compressed size
18561 header += hasData ? decToHex(compressedData.length, 4) : '\x00\x00\x00\x00';
18562 // uncompressed size
18563 header += hasData ? decToHex(data.length, 4) : '\x00\x00\x00\x00';
18564 // file name length
18565 header += decToHex(utfEncodedFileName.length, 2);
18566 // extra field length
18567 header += "\x00\x00";
18568
18569 return {
18570 header:header,
18571 compressedData:compressedData
18572 };
18573 };
18574
18575
18576 // return the actual prototype of JSZip
18577 return {
18578 /**
18579 * Read an existing zip and merge the data in the current JSZip object.
18580 * The implementation is in jszip-load.js, don't forget to include it.
18581 * @param {String|ArrayBuffer|Uint8Array} stream The stream to load
18582 * @param {Object} options Options for loading the stream.
18583 * options.base64 : is the stream in base64 ? default : false
18584 * @return {JSZip} the current JSZip object
18585 */
18586 load : function (stream, options) {
18587 throw new Error("Load method is not defined. Is the file jszip-load.js included ?");
18588 },
18589
18590 /**
18591 * Filter nested files/folders with the specified function.
18592 * @param {Function} search the predicate to use :
18593 * function (relativePath, file) {...}
18594 * It takes 2 arguments : the relative path and the file.
18595 * @return {Array} An array of matching elements.
18596 */
18597 filter : function (search) {
18598 var result = [], filename, relativePath, file, fileClone;
18599 for (filename in this.files) {
18600 if ( !this.files.hasOwnProperty(filename) ) { continue; }
18601 file = this.files[filename];
18602 // return a new object, don't let the user mess with our internal objects :)
18603 fileClone = new ZipObject(file.name, file.data, extend(file.options));
18604 relativePath = filename.slice(this.root.length, filename.length);
18605 if (filename.slice(0, this.root.length) === this.root && // the file is in the current root
18606 search(relativePath, fileClone)) { // and the file matches the function
18607 result.push(fileClone);
18608 }
18609 }
18610 return result;
18611 },
18612
18613 /**
18614 * Add a file to the zip file, or search a file.
18615 * @param {string|RegExp} name The name of the file to add (if data is defined),
18616 * the name of the file to find (if no data) or a regex to match files.
18617 * @param {String|ArrayBuffer|Uint8Array} data The file data, either raw or base64 encoded
18618 * @param {Object} o File options
18619 * @return {JSZip|Object|Array} this JSZip object (when adding a file),
18620 * a file (when searching by string) or an array of files (when searching by regex).
18621 */
18622 file : function(name, data, o) {
18623 if (arguments.length === 1) {
18624 if (name instanceof RegExp) {
18625 var regexp = name;
18626 return this.filter(function(relativePath, file) {
18627 return !file.options.dir && regexp.test(relativePath);
18628 });
18629 } else { // text
18630 return this.filter(function (relativePath, file) {
18631 return !file.options.dir && relativePath === name;
18632 })[0]||null;
18633 }
18634 } else { // more than one argument : we have data !
18635 name = this.root+name;
18636 fileAdd.call(this, name, data, o);
18637 }
18638 return this;
18639 },
18640
18641 /**
18642 * Add a directory to the zip file, or search.
18643 * @param {String|RegExp} arg The name of the directory to add, or a regex to search folders.
18644 * @return {JSZip} an object with the new directory as the root, or an array containing matching folders.
18645 */
18646 folder : function(arg) {
18647 if (!arg) {
18648 return this;
18649 }
18650
18651 if (arg instanceof RegExp) {
18652 return this.filter(function(relativePath, file) {
18653 return file.options.dir && arg.test(relativePath);
18654 });
18655 }
18656
18657 // else, name is a new folder
18658 var name = this.root + arg;
18659 var newFolder = folderAdd.call(this, name);
18660
18661 // Allow chaining by returning a new object with this folder as the root
18662 var ret = this.clone();
18663 ret.root = newFolder.name;
18664 return ret;
18665 },
18666
18667 /**
18668 * Delete a file, or a directory and all sub-files, from the zip
18669 * @param {string} name the name of the file to delete
18670 * @return {JSZip} this JSZip object
18671 */
18672 remove : function(name) {
18673 name = this.root + name;
18674 var file = this.files[name];
18675 if (!file) {
18676 // Look for any folders
18677 if (name.slice(-1) != "/") {
18678 name += "/";
18679 }
18680 file = this.files[name];
18681 }
18682
18683 if (file) {
18684 if (!file.options.dir) {
18685 // file
18686 delete this.files[name];
18687 } else {
18688 // folder
18689 var kids = this.filter(function (relativePath, file) {
18690 return file.name.slice(0, name.length) === name;
18691 });
18692 for (var i = 0; i < kids.length; i++) {
18693 delete this.files[kids[i].name];
18694 }
18695 }
18696 }
18697
18698 return this;
18699 },
18700
18701 /**
18702 * Generate the complete zip file
18703 * @param {Object} options the options to generate the zip file :
18704 * - base64, (deprecated, use type instead) true to generate base64.
18705 * - compression, "STORE" by default.
18706 * - type, "base64" by default. Values are : string, base64, uint8array, arraybuffer, blob.
18707 * @return {String|Uint8Array|ArrayBuffer|Blob} the zip file
18708 */
18709 generate : function(options) {
18710 options = extend(options || {}, {
18711 base64 : true,
18712 compression : "STORE",
18713 type : "base64"
18714 });
18715 var compression = options.compression.toUpperCase();
18716
18717 // The central directory, and files data
18718 var directory = [], files = [], fileOffset = 0;
18719
18720 if (!JSZip.compressions[compression]) {
18721 throw compression + " is not a valid compression method !";
18722 }
18723
18724 for (var name in this.files) {
18725 if ( !this.files.hasOwnProperty(name) ) { continue; }
18726
18727 var file = this.files[name];
18728
18729 var utfEncodedFileName = this.utf8encode(file.name);
18730
18731 var fileRecord = "",
18732 dirRecord = "",
18733 data = prepareLocalHeaderData.call(this, file, utfEncodedFileName, compression);
18734 fileRecord = JSZip.signature.LOCAL_FILE_HEADER + data.header + utfEncodedFileName + data.compressedData;
18735
18736 dirRecord = JSZip.signature.CENTRAL_FILE_HEADER +
18737 // version made by (00: DOS)
18738 "\x14\x00" +
18739 // file header (common to file and central directory)
18740 data.header +
18741 // file comment length
18742 "\x00\x00" +
18743 // disk number start
18744 "\x00\x00" +
18745 // internal file attributes TODO
18746 "\x00\x00" +
18747 // external file attributes
18748 (this.files[name].options.dir===true?"\x10\x00\x00\x00":"\x00\x00\x00\x00")+
18749 // relative offset of local header
18750 decToHex(fileOffset, 4) +
18751 // file name
18752 utfEncodedFileName;
18753
18754 fileOffset += fileRecord.length;
18755
18756 files.push(fileRecord);
18757 directory.push(dirRecord);
18758 }
18759
18760 var fileData = files.join("");
18761 var dirData = directory.join("");
18762
18763 var dirEnd = "";
18764
18765 // end of central dir signature
18766 dirEnd = JSZip.signature.CENTRAL_DIRECTORY_END +
18767 // number of this disk
18768 "\x00\x00" +
18769 // number of the disk with the start of the central directory
18770 "\x00\x00" +
18771 // total number of entries in the central directory on this disk
18772 decToHex(files.length, 2) +
18773 // total number of entries in the central directory
18774 decToHex(files.length, 2) +
18775 // size of the central directory 4 bytes
18776 decToHex(dirData.length, 4) +
18777 // offset of start of central directory with respect to the starting disk number
18778 decToHex(fileData.length, 4) +
18779 // .ZIP file comment length
18780 "\x00\x00";
18781
18782 var zip = fileData + dirData + dirEnd;
18783
18784
18785 switch(options.type.toLowerCase()) {
18786 case "uint8array" :
18787 return JSZip.utils.string2Uint8Array(zip);
18788 case "arraybuffer" :
18789 return JSZip.utils.string2Uint8Array(zip).buffer;
18790 case "blob" :
18791 return JSZip.utils.string2Blob(zip);
18792 case "base64" :
18793 return (options.base64) ? JSZipBase64.encode(zip) : zip;
18794 default : // case "string" :
18795 return zip;
18796 }
18797 },
18798
18799 /**
18800 *
18801 * Javascript crc32
18802 * http://www.webtoolkit.info/
18803 *
18804 */
18805 crc32 : function(str, crc) {
18806
18807 if (str === "" || typeof str === "undefined") {
18808 return 0;
18809 }
18810
18811 var table = [
18812 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
18813 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
18814 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
18815 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
18816 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
18817 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
18818 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
18819 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
18820 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
18821 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
18822 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
18823 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
18824 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
18825 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
18826 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
18827 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
18828 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
18829 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
18830 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
18831 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
18832 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
18833 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
18834 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
18835 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
18836 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
18837 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
18838 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
18839 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
18840 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
18841 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
18842 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
18843 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
18844 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
18845 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
18846 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
18847 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
18848 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
18849 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
18850 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
18851 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
18852 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
18853 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
18854 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
18855 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
18856 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
18857 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
18858 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
18859 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
18860 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
18861 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
18862 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
18863 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
18864 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
18865 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
18866 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
18867 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
18868 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
18869 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
18870 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
18871 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
18872 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
18873 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
18874 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
18875 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
18876 ];
18877
18878 if (typeof(crc) == "undefined") { crc = 0; }
18879 var x = 0;
18880 var y = 0;
18881
18882 crc = crc ^ (-1);
18883 for( var i = 0, iTop = str.length; i < iTop; i++ ) {
18884 y = ( crc ^ str.charCodeAt( i ) ) & 0xFF;
18885 x = table[y];
18886 crc = ( crc >>> 8 ) ^ x;
18887 }
18888
18889 return crc ^ (-1);
18890 },
18891
18892 // Inspired by http://my.opera.com/GreyWyvern/blog/show.dml/1725165
18893 clone : function() {
18894 var newObj = new JSZip();
18895 for (var i in this) {
18896 if (typeof this[i] !== "function") {
18897 newObj[i] = this[i];
18898 }
18899 }
18900 return newObj;
18901 },
18902
18903
18904 /**
18905 * http://www.webtoolkit.info/javascript-utf8.html
18906 */
18907 utf8encode : function (string) {
18908 string = string.replace(/\r\n/g,"\n");
18909 var utftext = "";
18910
18911 for (var n = 0; n < string.length; n++) {
18912
18913 var c = string.charCodeAt(n);
18914
18915 if (c < 128) {
18916 utftext += String.fromCharCode(c);
18917 } else if ((c > 127) && (c < 2048)) {
18918 utftext += String.fromCharCode((c >> 6) | 192);
18919 utftext += String.fromCharCode((c & 63) | 128);
18920 } else {
18921 utftext += String.fromCharCode((c >> 12) | 224);
18922 utftext += String.fromCharCode(((c >> 6) & 63) | 128);
18923 utftext += String.fromCharCode((c & 63) | 128);
18924 }
18925
18926 }
18927
18928 return utftext;
18929 },
18930
18931 /**
18932 * http://www.webtoolkit.info/javascript-utf8.html
18933 */
18934 utf8decode : function (utftext) {
18935 var string = "";
18936 var i = 0;
18937 var c = 0, c1 = 0, c2 = 0, c3 = 0;
18938
18939 while ( i < utftext.length ) {
18940
18941 c = utftext.charCodeAt(i);
18942
18943 if (c < 128) {
18944 string += String.fromCharCode(c);
18945 i++;
18946 } else if ((c > 191) && (c < 224)) {
18947 c2 = utftext.charCodeAt(i+1);
18948 string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
18949 i += 2;
18950 } else {
18951 c2 = utftext.charCodeAt(i+1);
18952 c3 = utftext.charCodeAt(i+2);
18953 string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
18954 i += 3;
18955 }
18956
18957 }
18958
18959 return string;
18960 }
18961 };
18962 }());
18963
18964 /*
18965 * Compression methods
18966 * This object is filled in as follow :
18967 * name : {
18968 * magic // the 2 bytes indentifying the compression method
18969 * compress // function, take the uncompressed content and return it compressed.
18970 * uncompress // function, take the compressed content and return it uncompressed.
18971 * }
18972 *
18973 * STORE is the default compression method, so it's included in this file.
18974 * Other methods should go to separated files : the user wants modularity.
18975 */
18976 JSZip.compressions = {
18977 "STORE" : {
18978 magic : "\x00\x00",
18979 compress : function (content) {
18980 return content; // no compression
18981 },
18982 uncompress : function (content) {
18983 return content; // no compression
18984 }
18985 }
18986 };
18987
18988 /*
18989 * List features that require a modern browser, and if the current browser support them.
18990 */
18991 JSZip.support = {
18992 // contains true if JSZip can read/generate ArrayBuffer, false otherwise.
18993 arraybuffer : (function(){
18994 return typeof ArrayBuffer !== "undefined" && typeof Uint8Array !== "undefined";
18995 })(),
18996 // contains true if JSZip can read/generate Uint8Array, false otherwise.
18997 uint8array : (function(){
18998 return typeof Uint8Array !== "undefined";
18999 })(),
19000 // contains true if JSZip can read/generate Blob, false otherwise.
19001 blob : (function(){
19002 // the spec started with BlobBuilder then replaced it with a construtor for Blob.
19003 // Result : we have browsers that :
19004 // * know the BlobBuilder (but with prefix)
19005 // * know the Blob constructor
19006 // * know about Blob but not about how to build them
19007 // About the "=== 0" test : if given the wrong type, it may be converted to a string.
19008 // Instead of an empty content, we will get "[object Uint8Array]" for example.
19009 if (typeof ArrayBuffer === "undefined") {
19010 return false;
19011 }
19012 var buffer = new ArrayBuffer(0);
19013 try {
19014 return new Blob([buffer], { type: "application/zip" }).size === 0;
19015 }
19016 catch(e) {}
19017
19018 try {
19019 var builder = new (window.BlobBuilder || window.WebKitBlobBuilder ||
19020 window.MozBlobBuilder || window.MSBlobBuilder)();
19021 builder.append(buffer);
19022 return builder.getBlob('application/zip').size === 0;
19023 }
19024 catch(e) {}
19025
19026 return false;
19027 })()
19028 };
19029
19030 JSZip.utils = {
19031 /**
19032 * Convert a string to a "binary string" : a string containing only char codes between 0 and 255.
19033 * @param {string} str the string to transform.
19034 * @return {String} the binary string.
19035 */
19036 string2binary : function (str) {
19037 var result = "";
19038 for (var i = 0; i < str.length; i++) {
19039 result += String.fromCharCode(str.charCodeAt(i) & 0xff);
19040 }
19041 return result;
19042 },
19043 /**
19044 * Create a Uint8Array from the string.
19045 * @param {string} str the string to transform.
19046 * @return {Uint8Array} the typed array.
19047 * @throws {Error} an Error if the browser doesn't support the requested feature.
19048 */
19049 string2Uint8Array : function (str) {
19050 if (!JSZip.support.uint8array) {
19051 throw new Error("Uint8Array is not supported by this browser");
19052 }
19053 var buffer = new ArrayBuffer(str.length);
19054 var bufferView = new Uint8Array(buffer);
19055 for(var i = 0; i < str.length; i++) {
19056 bufferView[i] = str.charCodeAt(i);
19057 }
19058
19059 return bufferView;
19060 },
19061
19062 /**
19063 * Create a string from the Uint8Array.
19064 * @param {Uint8Array} array the array to transform.
19065 * @return {string} the string.
19066 * @throws {Error} an Error if the browser doesn't support the requested feature.
19067 */
19068 uint8Array2String : function (array) {
19069 if (!JSZip.support.uint8array) {
19070 throw new Error("Uint8Array is not supported by this browser");
19071 }
19072 var result = "";
19073 for(var i = 0; i < array.length; i++) {
19074 result += String.fromCharCode(array[i]);
19075 }
19076
19077 return result;
19078 },
19079 /**
19080 * Create a blob from the given string.
19081 * @param {string} str the string to transform.
19082 * @return {Blob} the string.
19083 * @throws {Error} an Error if the browser doesn't support the requested feature.
19084 */
19085 string2Blob : function (str) {
19086 if (!JSZip.support.blob) {
19087 throw new Error("Blob is not supported by this browser");
19088 }
19089
19090 var buffer = JSZip.utils.string2Uint8Array(str).buffer;
19091 try {
19092 // Blob constructor
19093 return new Blob([buffer], { type: "application/zip" });
19094 }
19095 catch(e) {}
19096
19097 try {
19098 // deprecated, browser only, old way
19099 var builder = new (window.BlobBuilder || window.WebKitBlobBuilder ||
19100 window.MozBlobBuilder || window.MSBlobBuilder)();
19101 builder.append(buffer);
19102 return builder.getBlob('application/zip');
19103 }
19104 catch(e) {}
19105
19106 // well, fuck ?!
19107 throw new Error("Bug : can't construct the Blob.");
19108 }
19109 };
19110
19111 /**
19112 *
19113 * Base64 encode / decode
19114 * http://www.webtoolkit.info/
19115 *
19116 * Hacked so that it doesn't utf8 en/decode everything
19117 **/
19118 var JSZipBase64 = (function() {
19119 // private property
19120 var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
19121
19122 return {
19123 // public method for encoding
19124 encode : function(input, utf8) {
19125 var output = "";
19126 var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
19127 var i = 0;
19128
19129 while (i < input.length) {
19130
19131 chr1 = input.charCodeAt(i++);
19132 chr2 = input.charCodeAt(i++);
19133 chr3 = input.charCodeAt(i++);
19134
19135 enc1 = chr1 >> 2;
19136 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
19137 enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
19138 enc4 = chr3 & 63;
19139
19140 if (isNaN(chr2)) {
19141 enc3 = enc4 = 64;
19142 } else if (isNaN(chr3)) {
19143 enc4 = 64;
19144 }
19145
19146 output = output +
19147 _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
19148 _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
19149
19150 }
19151
19152 return output;
19153 },
19154
19155 // public method for decoding
19156 decode : function(input, utf8) {
19157 var output = "";
19158 var chr1, chr2, chr3;
19159 var enc1, enc2, enc3, enc4;
19160 var i = 0;
19161
19162 input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
19163
19164 while (i < input.length) {
19165
19166 enc1 = _keyStr.indexOf(input.charAt(i++));
19167 enc2 = _keyStr.indexOf(input.charAt(i++));
19168 enc3 = _keyStr.indexOf(input.charAt(i++));
19169 enc4 = _keyStr.indexOf(input.charAt(i++));
19170
19171 chr1 = (enc1 << 2) | (enc2 >> 4);
19172 chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
19173 chr3 = ((enc3 & 3) << 6) | enc4;
19174
19175 output = output + String.fromCharCode(chr1);
19176
19177 if (enc3 != 64) {
19178 output = output + String.fromCharCode(chr2);
19179 }
19180 if (enc4 != 64) {
19181 output = output + String.fromCharCode(chr3);
19182 }
19183
19184 }
19185
19186 return output;
19187
19188 }
19189 };
19190 }());
19191
19192 // enforcing Stuk's coding style
19193 // vim: set shiftwidth=3 softtabstop=3:
19194 /*
19195 * Port of a script by Masanao Izumo.
19196 *
19197 * Only changes : wrap all the variables in a function and add the
19198 * main function to JSZip (DEFLATE compression method).
19199 * Everything else was written by M. Izumo.
19200 *
19201 * Original code can be found here: http://www.onicos.com/staff/iz/amuse/javascript/expert/deflate.txt
19202 */
19203
19204 if(!JSZip) {
19205 throw "JSZip not defined";
19206 }
19207
19208 /*
19209 * Original:
19210 * http://www.onicos.com/staff/iz/amuse/javascript/expert/deflate.txt
19211 */
19212
19213 (function(){
19214
19215 /* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
19216 * Version: 1.0.1
19217 * LastModified: Dec 25 1999
19218 */
19219
19220 /* Interface:
19221 * data = zip_deflate(src);
19222 */
19223
19224 /* constant parameters */
19225 var zip_WSIZE = 32768; // Sliding Window size
19226 var zip_STORED_BLOCK = 0;
19227 var zip_STATIC_TREES = 1;
19228 var zip_DYN_TREES = 2;
19229
19230 /* for deflate */
19231 var zip_DEFAULT_LEVEL = 6;
19232 var zip_FULL_SEARCH = true;
19233 var zip_INBUFSIZ = 32768; // Input buffer size
19234 var zip_INBUF_EXTRA = 64; // Extra buffer
19235 var zip_OUTBUFSIZ = 1024 * 8;
19236 var zip_window_size = 2 * zip_WSIZE;
19237 var zip_MIN_MATCH = 3;
19238 var zip_MAX_MATCH = 258;
19239 var zip_BITS = 16;
19240 // for SMALL_MEM
19241 var zip_LIT_BUFSIZE = 0x2000;
19242 var zip_HASH_BITS = 13;
19243 // for MEDIUM_MEM
19244 // var zip_LIT_BUFSIZE = 0x4000;
19245 // var zip_HASH_BITS = 14;
19246 // for BIG_MEM
19247 // var zip_LIT_BUFSIZE = 0x8000;
19248 // var zip_HASH_BITS = 15;
19249 if(zip_LIT_BUFSIZE > zip_INBUFSIZ)
19250 alert("error: zip_INBUFSIZ is too small");
19251 if((zip_WSIZE<<1) > (1<<zip_BITS))
19252 alert("error: zip_WSIZE is too large");
19253 if(zip_HASH_BITS > zip_BITS-1)
19254 alert("error: zip_HASH_BITS is too large");
19255 if(zip_HASH_BITS < 8 || zip_MAX_MATCH != 258)
19256 alert("error: Code too clever");
19257 var zip_DIST_BUFSIZE = zip_LIT_BUFSIZE;
19258 var zip_HASH_SIZE = 1 << zip_HASH_BITS;
19259 var zip_HASH_MASK = zip_HASH_SIZE - 1;
19260 var zip_WMASK = zip_WSIZE - 1;
19261 var zip_NIL = 0; // Tail of hash chains
19262 var zip_TOO_FAR = 4096;
19263 var zip_MIN_LOOKAHEAD = zip_MAX_MATCH + zip_MIN_MATCH + 1;
19264 var zip_MAX_DIST = zip_WSIZE - zip_MIN_LOOKAHEAD;
19265 var zip_SMALLEST = 1;
19266 var zip_MAX_BITS = 15;
19267 var zip_MAX_BL_BITS = 7;
19268 var zip_LENGTH_CODES = 29;
19269 var zip_LITERALS =256;
19270 var zip_END_BLOCK = 256;
19271 var zip_L_CODES = zip_LITERALS + 1 + zip_LENGTH_CODES;
19272 var zip_D_CODES = 30;
19273 var zip_BL_CODES = 19;
19274 var zip_REP_3_6 = 16;
19275 var zip_REPZ_3_10 = 17;
19276 var zip_REPZ_11_138 = 18;
19277 var zip_HEAP_SIZE = 2 * zip_L_CODES + 1;
19278 var zip_H_SHIFT = parseInt((zip_HASH_BITS + zip_MIN_MATCH - 1) /
19279 zip_MIN_MATCH);
19280
19281 /* variables */
19282 var zip_free_queue;
19283 var zip_qhead, zip_qtail;
19284 var zip_initflag;
19285 var zip_outbuf = null;
19286 var zip_outcnt, zip_outoff;
19287 var zip_complete;
19288 var zip_window;
19289 var zip_d_buf;
19290 var zip_l_buf;
19291 var zip_prev;
19292 var zip_bi_buf;
19293 var zip_bi_valid;
19294 var zip_block_start;
19295 var zip_ins_h;
19296 var zip_hash_head;
19297 var zip_prev_match;
19298 var zip_match_available;
19299 var zip_match_length;
19300 var zip_prev_length;
19301 var zip_strstart;
19302 var zip_match_start;
19303 var zip_eofile;
19304 var zip_lookahead;
19305 var zip_max_chain_length;
19306 var zip_max_lazy_match;
19307 var zip_compr_level;
19308 var zip_good_match;
19309 var zip_nice_match;
19310 var zip_dyn_ltree;
19311 var zip_dyn_dtree;
19312 var zip_static_ltree;
19313 var zip_static_dtree;
19314 var zip_bl_tree;
19315 var zip_l_desc;
19316 var zip_d_desc;
19317 var zip_bl_desc;
19318 var zip_bl_count;
19319 var zip_heap;
19320 var zip_heap_len;
19321 var zip_heap_max;
19322 var zip_depth;
19323 var zip_length_code;
19324 var zip_dist_code;
19325 var zip_base_length;
19326 var zip_base_dist;
19327 var zip_flag_buf;
19328 var zip_last_lit;
19329 var zip_last_dist;
19330 var zip_last_flags;
19331 var zip_flags;
19332 var zip_flag_bit;
19333 var zip_opt_len;
19334 var zip_static_len;
19335 var zip_deflate_data;
19336 var zip_deflate_pos;
19337
19338 /* objects (deflate) */
19339
19340 var zip_DeflateCT = function() {
19341 this.fc = 0; // frequency count or bit string
19342 this.dl = 0; // father node in Huffman tree or length of bit string
19343 }
19344
19345 var zip_DeflateTreeDesc = function() {
19346 this.dyn_tree = null; // the dynamic tree
19347 this.static_tree = null; // corresponding static tree or NULL
19348 this.extra_bits = null; // extra bits for each code or NULL
19349 this.extra_base = 0; // base index for extra_bits
19350 this.elems = 0; // max number of elements in the tree
19351 this.max_length = 0; // max bit length for the codes
19352 this.max_code = 0; // largest code with non zero frequency
19353 }
19354
19355 /* Values for max_lazy_match, good_match and max_chain_length, depending on
19356 * the desired pack level (0..9). The values given below have been tuned to
19357 * exclude worst case performance for pathological files. Better values may be
19358 * found for specific files.
19359 */
19360 var zip_DeflateConfiguration = function(a, b, c, d) {
19361 this.good_length = a; // reduce lazy search above this match length
19362 this.max_lazy = b; // do not perform lazy search above this match length
19363 this.nice_length = c; // quit search above this match length
19364 this.max_chain = d;
19365 }
19366
19367 var zip_DeflateBuffer = function() {
19368 this.next = null;
19369 this.len = 0;
19370 this.ptr = new Array(zip_OUTBUFSIZ);
19371 this.off = 0;
19372 }
19373
19374 /* constant tables */
19375 var zip_extra_lbits = new Array(
19376 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0);
19377 var zip_extra_dbits = new Array(
19378 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13);
19379 var zip_extra_blbits = new Array(
19380 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7);
19381 var zip_bl_order = new Array(
19382 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15);
19383 var zip_configuration_table = new Array(
19384 new zip_DeflateConfiguration(0, 0, 0, 0),
19385 new zip_DeflateConfiguration(4, 4, 8, 4),
19386 new zip_DeflateConfiguration(4, 5, 16, 8),
19387 new zip_DeflateConfiguration(4, 6, 32, 32),
19388 new zip_DeflateConfiguration(4, 4, 16, 16),
19389 new zip_DeflateConfiguration(8, 16, 32, 32),
19390 new zip_DeflateConfiguration(8, 16, 128, 128),
19391 new zip_DeflateConfiguration(8, 32, 128, 256),
19392 new zip_DeflateConfiguration(32, 128, 258, 1024),
19393 new zip_DeflateConfiguration(32, 258, 258, 4096));
19394
19395
19396 /* routines (deflate) */
19397
19398 var zip_deflate_start = function(level) {
19399 var i;
19400
19401 if(!level)
19402 level = zip_DEFAULT_LEVEL;
19403 else if(level < 1)
19404 level = 1;
19405 else if(level > 9)
19406 level = 9;
19407
19408 zip_compr_level = level;
19409 zip_initflag = false;
19410 zip_eofile = false;
19411 if(zip_outbuf != null)
19412 return;
19413
19414 zip_free_queue = zip_qhead = zip_qtail = null;
19415 zip_outbuf = new Array(zip_OUTBUFSIZ);
19416 zip_window = new Array(zip_window_size);
19417 zip_d_buf = new Array(zip_DIST_BUFSIZE);
19418 zip_l_buf = new Array(zip_INBUFSIZ + zip_INBUF_EXTRA);
19419 zip_prev = new Array(1 << zip_BITS);
19420 zip_dyn_ltree = new Array(zip_HEAP_SIZE);
19421 for(i = 0; i < zip_HEAP_SIZE; i++)
19422 zip_dyn_ltree[i] = new zip_DeflateCT();
19423 zip_dyn_dtree = new Array(2*zip_D_CODES+1);
19424 for(i = 0; i < 2*zip_D_CODES+1; i++)
19425 zip_dyn_dtree[i] = new zip_DeflateCT();
19426 zip_static_ltree = new Array(zip_L_CODES+2);
19427 for(i = 0; i < zip_L_CODES+2; i++)
19428 zip_static_ltree[i] = new zip_DeflateCT();
19429 zip_static_dtree = new Array(zip_D_CODES);
19430 for(i = 0; i < zip_D_CODES; i++)
19431 zip_static_dtree[i] = new zip_DeflateCT();
19432 zip_bl_tree = new Array(2*zip_BL_CODES+1);
19433 for(i = 0; i < 2*zip_BL_CODES+1; i++)
19434 zip_bl_tree[i] = new zip_DeflateCT();
19435 zip_l_desc = new zip_DeflateTreeDesc();
19436 zip_d_desc = new zip_DeflateTreeDesc();
19437 zip_bl_desc = new zip_DeflateTreeDesc();
19438 zip_bl_count = new Array(zip_MAX_BITS+1);
19439 zip_heap = new Array(2*zip_L_CODES+1);
19440 zip_depth = new Array(2*zip_L_CODES+1);
19441 zip_length_code = new Array(zip_MAX_MATCH-zip_MIN_MATCH+1);
19442 zip_dist_code = new Array(512);
19443 zip_base_length = new Array(zip_LENGTH_CODES);
19444 zip_base_dist = new Array(zip_D_CODES);
19445 zip_flag_buf = new Array(parseInt(zip_LIT_BUFSIZE / 8));
19446 }
19447
19448 var zip_deflate_end = function() {
19449 zip_free_queue = zip_qhead = zip_qtail = null;
19450 zip_outbuf = null;
19451 zip_window = null;
19452 zip_d_buf = null;
19453 zip_l_buf = null;
19454 zip_prev = null;
19455 zip_dyn_ltree = null;
19456 zip_dyn_dtree = null;
19457 zip_static_ltree = null;
19458 zip_static_dtree = null;
19459 zip_bl_tree = null;
19460 zip_l_desc = null;
19461 zip_d_desc = null;
19462 zip_bl_desc = null;
19463 zip_bl_count = null;
19464 zip_heap = null;
19465 zip_depth = null;
19466 zip_length_code = null;
19467 zip_dist_code = null;
19468 zip_base_length = null;
19469 zip_base_dist = null;
19470 zip_flag_buf = null;
19471 }
19472
19473 var zip_reuse_queue = function(p) {
19474 p.next = zip_free_queue;
19475 zip_free_queue = p;
19476 }
19477
19478 var zip_new_queue = function() {
19479 var p;
19480
19481 if(zip_free_queue != null)
19482 {
19483 p = zip_free_queue;
19484 zip_free_queue = zip_free_queue.next;
19485 }
19486 else
19487 p = new zip_DeflateBuffer();
19488 p.next = null;
19489 p.len = p.off = 0;
19490
19491 return p;
19492 }
19493
19494 var zip_head1 = function(i) {
19495 return zip_prev[zip_WSIZE + i];
19496 }
19497
19498 var zip_head2 = function(i, val) {
19499 return zip_prev[zip_WSIZE + i] = val;
19500 }
19501
19502 /* put_byte is used for the compressed output, put_ubyte for the
19503 * uncompressed output. However unlzw() uses window for its
19504 * suffix table instead of its output buffer, so it does not use put_ubyte
19505 * (to be cleaned up).
19506 */
19507 var zip_put_byte = function(c) {
19508 zip_outbuf[zip_outoff + zip_outcnt++] = c;
19509 if(zip_outoff + zip_outcnt == zip_OUTBUFSIZ)
19510 zip_qoutbuf();
19511 }
19512
19513 /* Output a 16 bit value, lsb first */
19514 var zip_put_short = function(w) {
19515 w &= 0xffff;
19516 if(zip_outoff + zip_outcnt < zip_OUTBUFSIZ - 2) {
19517 zip_outbuf[zip_outoff + zip_outcnt++] = (w & 0xff);
19518 zip_outbuf[zip_outoff + zip_outcnt++] = (w >>> 8);
19519 } else {
19520 zip_put_byte(w & 0xff);
19521 zip_put_byte(w >>> 8);
19522 }
19523 }
19524
19525 /* ==========================================================================
19526 * Insert string s in the dictionary and set match_head to the previous head
19527 * of the hash chain (the most recent string with same hash key). Return
19528 * the previous length of the hash chain.
19529 * IN assertion: all calls to to INSERT_STRING are made with consecutive
19530 * input characters and the first MIN_MATCH bytes of s are valid
19531 * (except for the last MIN_MATCH-1 bytes of the input file).
19532 */
19533 var zip_INSERT_STRING = function() {
19534 zip_ins_h = ((zip_ins_h << zip_H_SHIFT)
19535 ^ (zip_window[zip_strstart + zip_MIN_MATCH - 1] & 0xff))
19536 & zip_HASH_MASK;
19537 zip_hash_head = zip_head1(zip_ins_h);
19538 zip_prev[zip_strstart & zip_WMASK] = zip_hash_head;
19539 zip_head2(zip_ins_h, zip_strstart);
19540 }
19541
19542 /* Send a code of the given tree. c and tree must not have side effects */
19543 var zip_SEND_CODE = function(c, tree) {
19544 zip_send_bits(tree[c].fc, tree[c].dl);
19545 }
19546
19547 /* Mapping from a distance to a distance code. dist is the distance - 1 and
19548 * must not have side effects. dist_code[256] and dist_code[257] are never
19549 * used.
19550 */
19551 var zip_D_CODE = function(dist) {
19552 return (dist < 256 ? zip_dist_code[dist]
19553 : zip_dist_code[256 + (dist>>7)]) & 0xff;
19554 }
19555
19556 /* ==========================================================================
19557 * Compares to subtrees, using the tree depth as tie breaker when
19558 * the subtrees have equal frequency. This minimizes the worst case length.
19559 */
19560 var zip_SMALLER = function(tree, n, m) {
19561 return tree[n].fc < tree[m].fc ||
19562 (tree[n].fc == tree[m].fc && zip_depth[n] <= zip_depth[m]);
19563 }
19564
19565 /* ==========================================================================
19566 * read string data
19567 */
19568 var zip_read_buff = function(buff, offset, n) {
19569 var i;
19570 for(i = 0; i < n && zip_deflate_pos < zip_deflate_data.length; i++)
19571 buff[offset + i] =
19572 zip_deflate_data.charCodeAt(zip_deflate_pos++) & 0xff;
19573 return i;
19574 }
19575
19576 /* ==========================================================================
19577 * Initialize the "longest match" routines for a new file
19578 */
19579 var zip_lm_init = function() {
19580 var j;
19581
19582 /* Initialize the hash table. */
19583 for(j = 0; j < zip_HASH_SIZE; j++)
19584 // zip_head2(j, zip_NIL);
19585 zip_prev[zip_WSIZE + j] = 0;
19586 /* prev will be initialized on the fly */
19587
19588 /* Set the default configuration parameters:
19589 */
19590 zip_max_lazy_match = zip_configuration_table[zip_compr_level].max_lazy;
19591 zip_good_match = zip_configuration_table[zip_compr_level].good_length;
19592 if(!zip_FULL_SEARCH)
19593 zip_nice_match = zip_configuration_table[zip_compr_level].nice_length;
19594 zip_max_chain_length = zip_configuration_table[zip_compr_level].max_chain;
19595
19596 zip_strstart = 0;
19597 zip_block_start = 0;
19598
19599 zip_lookahead = zip_read_buff(zip_window, 0, 2 * zip_WSIZE);
19600 if(zip_lookahead <= 0) {
19601 zip_eofile = true;
19602 zip_lookahead = 0;
19603 return;
19604 }
19605 zip_eofile = false;
19606 /* Make sure that we always have enough lookahead. This is important
19607 * if input comes from a device such as a tty.
19608 */
19609 while(zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile)
19610 zip_fill_window();
19611
19612 /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
19613 * not important since only literal bytes will be emitted.
19614 */
19615 zip_ins_h = 0;
19616 for(j = 0; j < zip_MIN_MATCH - 1; j++) {
19617 // UPDATE_HASH(ins_h, window[j]);
19618 zip_ins_h = ((zip_ins_h << zip_H_SHIFT) ^ (zip_window[j] & 0xff)) & zip_HASH_MASK;
19619 }
19620 }
19621
19622 /* ==========================================================================
19623 * Set match_start to the longest match starting at the given string and
19624 * return its length. Matches shorter or equal to prev_length are discarded,
19625 * in which case the result is equal to prev_length and match_start is
19626 * garbage.
19627 * IN assertions: cur_match is the head of the hash chain for the current
19628 * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
19629 */
19630 var zip_longest_match = function(cur_match) {
19631 var chain_length = zip_max_chain_length; // max hash chain length
19632 var scanp = zip_strstart; // current string
19633 var matchp; // matched string
19634 var len; // length of current match
19635 var best_len = zip_prev_length; // best match length so far
19636
19637 /* Stop when cur_match becomes <= limit. To simplify the code,
19638 * we prevent matches with the string of window index 0.
19639 */
19640 var limit = (zip_strstart > zip_MAX_DIST ? zip_strstart - zip_MAX_DIST : zip_NIL);
19641
19642 var strendp = zip_strstart + zip_MAX_MATCH;
19643 var scan_end1 = zip_window[scanp + best_len - 1];
19644 var scan_end = zip_window[scanp + best_len];
19645
19646 /* Do not waste too much time if we already have a good match: */
19647 if(zip_prev_length >= zip_good_match)
19648 chain_length >>= 2;
19649
19650 // Assert(encoder->strstart <= window_size-MIN_LOOKAHEAD, "insufficient lookahead");
19651
19652 do {
19653 // Assert(cur_match < encoder->strstart, "no future");
19654 matchp = cur_match;
19655
19656 /* Skip to next match if the match length cannot increase
19657 * or if the match length is less than 2:
19658 */
19659 if(zip_window[matchp + best_len] != scan_end ||
19660 zip_window[matchp + best_len - 1] != scan_end1 ||
19661 zip_window[matchp] != zip_window[scanp] ||
19662 zip_window[++matchp] != zip_window[scanp + 1]) {
19663 continue;
19664 }
19665
19666 /* The check at best_len-1 can be removed because it will be made
19667 * again later. (This heuristic is not always a win.)
19668 * It is not necessary to compare scan[2] and match[2] since they
19669 * are always equal when the other bytes match, given that
19670 * the hash keys are equal and that HASH_BITS >= 8.
19671 */
19672 scanp += 2;
19673 matchp++;
19674
19675 /* We check for insufficient lookahead only every 8th comparison;
19676 * the 256th check will be made at strstart+258.
19677 */
19678 do {
19679 } while(zip_window[++scanp] == zip_window[++matchp] &&
19680 zip_window[++scanp] == zip_window[++matchp] &&
19681 zip_window[++scanp] == zip_window[++matchp] &&
19682 zip_window[++scanp] == zip_window[++matchp] &&
19683 zip_window[++scanp] == zip_window[++matchp] &&
19684 zip_window[++scanp] == zip_window[++matchp] &&
19685 zip_window[++scanp] == zip_window[++matchp] &&
19686 zip_window[++scanp] == zip_window[++matchp] &&
19687 scanp < strendp);
19688
19689 len = zip_MAX_MATCH - (strendp - scanp);
19690 scanp = strendp - zip_MAX_MATCH;
19691
19692 if(len > best_len) {
19693 zip_match_start = cur_match;
19694 best_len = len;
19695 if(zip_FULL_SEARCH) {
19696 if(len >= zip_MAX_MATCH) break;
19697 } else {
19698 if(len >= zip_nice_match) break;
19699 }
19700
19701 scan_end1 = zip_window[scanp + best_len-1];
19702 scan_end = zip_window[scanp + best_len];
19703 }
19704 } while((cur_match = zip_prev[cur_match & zip_WMASK]) > limit
19705 && --chain_length != 0);
19706
19707 return best_len;
19708 }
19709
19710 /* ==========================================================================
19711 * Fill the window when the lookahead becomes insufficient.
19712 * Updates strstart and lookahead, and sets eofile if end of input file.
19713 * IN assertion: lookahead < MIN_LOOKAHEAD && strstart + lookahead > 0
19714 * OUT assertions: at least one byte has been read, or eofile is set;
19715 * file reads are performed for at least two bytes (required for the
19716 * translate_eol option).
19717 */
19718 var zip_fill_window = function() {
19719 var n, m;
19720
19721 // Amount of free space at the end of the window.
19722 var more = zip_window_size - zip_lookahead - zip_strstart;
19723
19724 /* If the window is almost full and there is insufficient lookahead,
19725 * move the upper half to the lower one to make room in the upper half.
19726 */
19727 if(more == -1) {
19728 /* Very unlikely, but possible on 16 bit machine if strstart == 0
19729 * and lookahead == 1 (input done one byte at time)
19730 */
19731 more--;
19732 } else if(zip_strstart >= zip_WSIZE + zip_MAX_DIST) {
19733 /* By the IN assertion, the window is not empty so we can't confuse
19734 * more == 0 with more == 64K on a 16 bit machine.
19735 */
19736 // Assert(window_size == (ulg)2*WSIZE, "no sliding with BIG_MEM");
19737
19738 // System.arraycopy(window, WSIZE, window, 0, WSIZE);
19739 for(n = 0; n < zip_WSIZE; n++)
19740 zip_window[n] = zip_window[n + zip_WSIZE];
19741
19742 zip_match_start -= zip_WSIZE;
19743 zip_strstart -= zip_WSIZE; /* we now have strstart >= MAX_DIST: */
19744 zip_block_start -= zip_WSIZE;
19745
19746 for(n = 0; n < zip_HASH_SIZE; n++) {
19747 m = zip_head1(n);
19748 zip_head2(n, m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL);
19749 }
19750 for(n = 0; n < zip_WSIZE; n++) {
19751 /* If n is not on any hash chain, prev[n] is garbage but
19752 * its value will never be used.
19753 */
19754 m = zip_prev[n];
19755 zip_prev[n] = (m >= zip_WSIZE ? m - zip_WSIZE : zip_NIL);
19756 }
19757 more += zip_WSIZE;
19758 }
19759 // At this point, more >= 2
19760 if(!zip_eofile) {
19761 n = zip_read_buff(zip_window, zip_strstart + zip_lookahead, more);
19762 if(n <= 0)
19763 zip_eofile = true;
19764 else
19765 zip_lookahead += n;
19766 }
19767 }
19768
19769 /* ==========================================================================
19770 * Processes a new input file and return its compressed length. This
19771 * function does not perform lazy evaluationof matches and inserts
19772 * new strings in the dictionary only for unmatched strings or for short
19773 * matches. It is used only for the fast compression options.
19774 */
19775 var zip_deflate_fast = function() {
19776 while(zip_lookahead != 0 && zip_qhead == null) {
19777 var flush; // set if current block must be flushed
19778
19779 /* Insert the string window[strstart .. strstart+2] in the
19780 * dictionary, and set hash_head to the head of the hash chain:
19781 */
19782 zip_INSERT_STRING();
19783
19784 /* Find the longest match, discarding those <= prev_length.
19785 * At this point we have always match_length < MIN_MATCH
19786 */
19787 if(zip_hash_head != zip_NIL &&
19788 zip_strstart - zip_hash_head <= zip_MAX_DIST) {
19789 /* To simplify the code, we prevent matches with the string
19790 * of window index 0 (in particular we have to avoid a match
19791 * of the string with itself at the start of the input file).
19792 */
19793 zip_match_length = zip_longest_match(zip_hash_head);
19794 /* longest_match() sets match_start */
19795 if(zip_match_length > zip_lookahead)
19796 zip_match_length = zip_lookahead;
19797 }
19798 if(zip_match_length >= zip_MIN_MATCH) {
19799 // check_match(strstart, match_start, match_length);
19800
19801 flush = zip_ct_tally(zip_strstart - zip_match_start,
19802 zip_match_length - zip_MIN_MATCH);
19803 zip_lookahead -= zip_match_length;
19804
19805 /* Insert new strings in the hash table only if the match length
19806 * is not too large. This saves time but degrades compression.
19807 */
19808 if(zip_match_length <= zip_max_lazy_match) {
19809 zip_match_length--; // string at strstart already in hash table
19810 do {
19811 zip_strstart++;
19812 zip_INSERT_STRING();
19813 /* strstart never exceeds WSIZE-MAX_MATCH, so there are
19814 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
19815 * these bytes are garbage, but it does not matter since
19816 * the next lookahead bytes will be emitted as literals.
19817 */
19818 } while(--zip_match_length != 0);
19819 zip_strstart++;
19820 } else {
19821 zip_strstart += zip_match_length;
19822 zip_match_length = 0;
19823 zip_ins_h = zip_window[zip_strstart] & 0xff;
19824 // UPDATE_HASH(ins_h, window[strstart + 1]);
19825 zip_ins_h = ((zip_ins_h<<zip_H_SHIFT) ^ (zip_window[zip_strstart + 1] & 0xff)) & zip_HASH_MASK;
19826
19827 //#if MIN_MATCH != 3
19828 // Call UPDATE_HASH() MIN_MATCH-3 more times
19829 //#endif
19830
19831 }
19832 } else {
19833 /* No match, output a literal byte */
19834 flush = zip_ct_tally(0, zip_window[zip_strstart] & 0xff);
19835 zip_lookahead--;
19836 zip_strstart++;
19837 }
19838 if(flush) {
19839 zip_flush_block(0);
19840 zip_block_start = zip_strstart;
19841 }
19842
19843 /* Make sure that we always have enough lookahead, except
19844 * at the end of the input file. We need MAX_MATCH bytes
19845 * for the next match, plus MIN_MATCH bytes to insert the
19846 * string following the next match.
19847 */
19848 while(zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile)
19849 zip_fill_window();
19850 }
19851 }
19852
19853 var zip_deflate_better = function() {
19854 /* Process the input block. */
19855 while(zip_lookahead != 0 && zip_qhead == null) {
19856 /* Insert the string window[strstart .. strstart+2] in the
19857 * dictionary, and set hash_head to the head of the hash chain:
19858 */
19859 zip_INSERT_STRING();
19860
19861 /* Find the longest match, discarding those <= prev_length.
19862 */
19863 zip_prev_length = zip_match_length;
19864 zip_prev_match = zip_match_start;
19865 zip_match_length = zip_MIN_MATCH - 1;
19866
19867 if(zip_hash_head != zip_NIL &&
19868 zip_prev_length < zip_max_lazy_match &&
19869 zip_strstart - zip_hash_head <= zip_MAX_DIST) {
19870 /* To simplify the code, we prevent matches with the string
19871 * of window index 0 (in particular we have to avoid a match
19872 * of the string with itself at the start of the input file).
19873 */
19874 zip_match_length = zip_longest_match(zip_hash_head);
19875 /* longest_match() sets match_start */
19876 if(zip_match_length > zip_lookahead)
19877 zip_match_length = zip_lookahead;
19878
19879 /* Ignore a length 3 match if it is too distant: */
19880 if(zip_match_length == zip_MIN_MATCH &&
19881 zip_strstart - zip_match_start > zip_TOO_FAR) {
19882 /* If prev_match is also MIN_MATCH, match_start is garbage
19883 * but we will ignore the current match anyway.
19884 */
19885 zip_match_length--;
19886 }
19887 }
19888 /* If there was a match at the previous step and the current
19889 * match is not better, output the previous match:
19890 */
19891 if(zip_prev_length >= zip_MIN_MATCH &&
19892 zip_match_length <= zip_prev_length) {
19893 var flush; // set if current block must be flushed
19894
19895 // check_match(strstart - 1, prev_match, prev_length);
19896 flush = zip_ct_tally(zip_strstart - 1 - zip_prev_match,
19897 zip_prev_length - zip_MIN_MATCH);
19898
19899 /* Insert in hash table all strings up to the end of the match.
19900 * strstart-1 and strstart are already inserted.
19901 */
19902 zip_lookahead -= zip_prev_length - 1;
19903 zip_prev_length -= 2;
19904 do {
19905 zip_strstart++;
19906 zip_INSERT_STRING();
19907 /* strstart never exceeds WSIZE-MAX_MATCH, so there are
19908 * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
19909 * these bytes are garbage, but it does not matter since the
19910 * next lookahead bytes will always be emitted as literals.
19911 */
19912 } while(--zip_prev_length != 0);
19913 zip_match_available = 0;
19914 zip_match_length = zip_MIN_MATCH - 1;
19915 zip_strstart++;
19916 if(flush) {
19917 zip_flush_block(0);
19918 zip_block_start = zip_strstart;
19919 }
19920 } else if(zip_match_available != 0) {
19921 /* If there was no match at the previous position, output a
19922 * single literal. If there was a match but the current match
19923 * is longer, truncate the previous match to a single literal.
19924 */
19925 if(zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff)) {
19926 zip_flush_block(0);
19927 zip_block_start = zip_strstart;
19928 }
19929 zip_strstart++;
19930 zip_lookahead--;
19931 } else {
19932 /* There is no previous match to compare with, wait for
19933 * the next step to decide.
19934 */
19935 zip_match_available = 1;
19936 zip_strstart++;
19937 zip_lookahead--;
19938 }
19939
19940 /* Make sure that we always have enough lookahead, except
19941 * at the end of the input file. We need MAX_MATCH bytes
19942 * for the next match, plus MIN_MATCH bytes to insert the
19943 * string following the next match.
19944 */
19945 while(zip_lookahead < zip_MIN_LOOKAHEAD && !zip_eofile)
19946 zip_fill_window();
19947 }
19948 }
19949
19950 var zip_init_deflate = function() {
19951 if(zip_eofile)
19952 return;
19953 zip_bi_buf = 0;
19954 zip_bi_valid = 0;
19955 zip_ct_init();
19956 zip_lm_init();
19957
19958 zip_qhead = null;
19959 zip_outcnt = 0;
19960 zip_outoff = 0;
19961
19962 if(zip_compr_level <= 3)
19963 {
19964 zip_prev_length = zip_MIN_MATCH - 1;
19965 zip_match_length = 0;
19966 }
19967 else
19968 {
19969 zip_match_length = zip_MIN_MATCH - 1;
19970 zip_match_available = 0;
19971 }
19972
19973 zip_complete = false;
19974 }
19975
19976 /* ==========================================================================
19977 * Same as above, but achieves better compression. We use a lazy
19978 * evaluation for matches: a match is finally adopted only if there is
19979 * no better match at the next window position.
19980 */
19981 var zip_deflate_internal = function(buff, off, buff_size) {
19982 var n;
19983
19984 if(!zip_initflag)
19985 {
19986 zip_init_deflate();
19987 zip_initflag = true;
19988 if(zip_lookahead == 0) { // empty
19989 zip_complete = true;
19990 return 0;
19991 }
19992 }
19993
19994 if((n = zip_qcopy(buff, off, buff_size)) == buff_size)
19995 return buff_size;
19996
19997 if(zip_complete)
19998 return n;
19999
20000 if(zip_compr_level <= 3) // optimized for speed
20001 zip_deflate_fast();
20002 else
20003 zip_deflate_better();
20004 if(zip_lookahead == 0) {
20005 if(zip_match_available != 0)
20006 zip_ct_tally(0, zip_window[zip_strstart - 1] & 0xff);
20007 zip_flush_block(1);
20008 zip_complete = true;
20009 }
20010 return n + zip_qcopy(buff, n + off, buff_size - n);
20011 }
20012
20013 var zip_qcopy = function(buff, off, buff_size) {
20014 var n, i, j;
20015
20016 n = 0;
20017 while(zip_qhead != null && n < buff_size)
20018 {
20019 i = buff_size - n;
20020 if(i > zip_qhead.len)
20021 i = zip_qhead.len;
20022 // System.arraycopy(qhead.ptr, qhead.off, buff, off + n, i);
20023 for(j = 0; j < i; j++)
20024 buff[off + n + j] = zip_qhead.ptr[zip_qhead.off + j];
20025
20026 zip_qhead.off += i;
20027 zip_qhead.len -= i;
20028 n += i;
20029 if(zip_qhead.len == 0) {
20030 var p;
20031 p = zip_qhead;
20032 zip_qhead = zip_qhead.next;
20033 zip_reuse_queue(p);
20034 }
20035 }
20036
20037 if(n == buff_size)
20038 return n;
20039
20040 if(zip_outoff < zip_outcnt) {
20041 i = buff_size - n;
20042 if(i > zip_outcnt - zip_outoff)
20043 i = zip_outcnt - zip_outoff;
20044 // System.arraycopy(outbuf, outoff, buff, off + n, i);
20045 for(j = 0; j < i; j++)
20046 buff[off + n + j] = zip_outbuf[zip_outoff + j];
20047 zip_outoff += i;
20048 n += i;
20049 if(zip_outcnt == zip_outoff)
20050 zip_outcnt = zip_outoff = 0;
20051 }
20052 return n;
20053 }
20054
20055 /* ==========================================================================
20056 * Allocate the match buffer, initialize the various tables and save the
20057 * location of the internal file attribute (ascii/binary) and method
20058 * (DEFLATE/STORE).
20059 */
20060 var zip_ct_init = function() {
20061 var n; // iterates over tree elements
20062 var bits; // bit counter
20063 var length; // length value
20064 var code; // code value
20065 var dist; // distance index
20066
20067 if(zip_static_dtree[0].dl != 0) return; // ct_init already called
20068
20069 zip_l_desc.dyn_tree = zip_dyn_ltree;
20070 zip_l_desc.static_tree = zip_static_ltree;
20071 zip_l_desc.extra_bits = zip_extra_lbits;
20072 zip_l_desc.extra_base = zip_LITERALS + 1;
20073 zip_l_desc.elems = zip_L_CODES;
20074 zip_l_desc.max_length = zip_MAX_BITS;
20075 zip_l_desc.max_code = 0;
20076
20077 zip_d_desc.dyn_tree = zip_dyn_dtree;
20078 zip_d_desc.static_tree = zip_static_dtree;
20079 zip_d_desc.extra_bits = zip_extra_dbits;
20080 zip_d_desc.extra_base = 0;
20081 zip_d_desc.elems = zip_D_CODES;
20082 zip_d_desc.max_length = zip_MAX_BITS;
20083 zip_d_desc.max_code = 0;
20084
20085 zip_bl_desc.dyn_tree = zip_bl_tree;
20086 zip_bl_desc.static_tree = null;
20087 zip_bl_desc.extra_bits = zip_extra_blbits;
20088 zip_bl_desc.extra_base = 0;
20089 zip_bl_desc.elems = zip_BL_CODES;
20090 zip_bl_desc.max_length = zip_MAX_BL_BITS;
20091 zip_bl_desc.max_code = 0;
20092
20093 // Initialize the mapping length (0..255) -> length code (0..28)
20094 length = 0;
20095 for(code = 0; code < zip_LENGTH_CODES-1; code++) {
20096 zip_base_length[code] = length;
20097 for(n = 0; n < (1<<zip_extra_lbits[code]); n++)
20098 zip_length_code[length++] = code;
20099 }
20100 // Assert (length == 256, "ct_init: length != 256");
20101
20102 /* Note that the length 255 (match length 258) can be represented
20103 * in two different ways: code 284 + 5 bits or code 285, so we
20104 * overwrite length_code[255] to use the best encoding:
20105 */
20106 zip_length_code[length-1] = code;
20107
20108 /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
20109 dist = 0;
20110 for(code = 0 ; code < 16; code++) {
20111 zip_base_dist[code] = dist;
20112 for(n = 0; n < (1<<zip_extra_dbits[code]); n++) {
20113 zip_dist_code[dist++] = code;
20114 }
20115 }
20116 // Assert (dist == 256, "ct_init: dist != 256");
20117 dist >>= 7; // from now on, all distances are divided by 128
20118 for( ; code < zip_D_CODES; code++) {
20119 zip_base_dist[code] = dist << 7;
20120 for(n = 0; n < (1<<(zip_extra_dbits[code]-7)); n++)
20121 zip_dist_code[256 + dist++] = code;
20122 }
20123 // Assert (dist == 256, "ct_init: 256+dist != 512");
20124
20125 // Construct the codes of the static literal tree
20126 for(bits = 0; bits <= zip_MAX_BITS; bits++)
20127 zip_bl_count[bits] = 0;
20128 n = 0;
20129 while(n <= 143) { zip_static_ltree[n++].dl = 8; zip_bl_count[8]++; }
20130 while(n <= 255) { zip_static_ltree[n++].dl = 9; zip_bl_count[9]++; }
20131 while(n <= 279) { zip_static_ltree[n++].dl = 7; zip_bl_count[7]++; }
20132 while(n <= 287) { zip_static_ltree[n++].dl = 8; zip_bl_count[8]++; }
20133 /* Codes 286 and 287 do not exist, but we must include them in the
20134 * tree construction to get a canonical Huffman tree (longest code
20135 * all ones)
20136 */
20137 zip_gen_codes(zip_static_ltree, zip_L_CODES + 1);
20138
20139 /* The static distance tree is trivial: */
20140 for(n = 0; n < zip_D_CODES; n++) {
20141 zip_static_dtree[n].dl = 5;
20142 zip_static_dtree[n].fc = zip_bi_reverse(n, 5);
20143 }
20144
20145 // Initialize the first block of the first file:
20146 zip_init_block();
20147 }
20148
20149 /* ==========================================================================
20150 * Initialize a new block.
20151 */
20152 var zip_init_block = function() {
20153 var n; // iterates over tree elements
20154
20155 // Initialize the trees.
20156 for(n = 0; n < zip_L_CODES; n++) zip_dyn_ltree[n].fc = 0;
20157 for(n = 0; n < zip_D_CODES; n++) zip_dyn_dtree[n].fc = 0;
20158 for(n = 0; n < zip_BL_CODES; n++) zip_bl_tree[n].fc = 0;
20159
20160 zip_dyn_ltree[zip_END_BLOCK].fc = 1;
20161 zip_opt_len = zip_static_len = 0;
20162 zip_last_lit = zip_last_dist = zip_last_flags = 0;
20163 zip_flags = 0;
20164 zip_flag_bit = 1;
20165 }
20166
20167 /* ==========================================================================
20168 * Restore the heap property by moving down the tree starting at node k,
20169 * exchanging a node with the smallest of its two sons if necessary, stopping
20170 * when the heap property is re-established (each father smaller than its
20171 * two sons).
20172 */
20173 var zip_pqdownheap = function(
20174 tree, // the tree to restore
20175 k) { // node to move down
20176 var v = zip_heap[k];
20177 var j = k << 1; // left son of k
20178
20179 while(j <= zip_heap_len) {
20180 // Set j to the smallest of the two sons:
20181 if(j < zip_heap_len &&
20182 zip_SMALLER(tree, zip_heap[j + 1], zip_heap[j]))
20183 j++;
20184
20185 // Exit if v is smaller than both sons
20186 if(zip_SMALLER(tree, v, zip_heap[j]))
20187 break;
20188
20189 // Exchange v with the smallest son
20190 zip_heap[k] = zip_heap[j];
20191 k = j;
20192
20193 // And continue down the tree, setting j to the left son of k
20194 j <<= 1;
20195 }
20196 zip_heap[k] = v;
20197 }
20198
20199 /* ==========================================================================
20200 * Compute the optimal bit lengths for a tree and update the total bit length
20201 * for the current block.
20202 * IN assertion: the fields freq and dad are set, heap[heap_max] and
20203 * above are the tree nodes sorted by increasing frequency.
20204 * OUT assertions: the field len is set to the optimal bit length, the
20205 * array bl_count contains the frequencies for each bit length.
20206 * The length opt_len is updated; static_len is also updated if stree is
20207 * not null.
20208 */
20209 var zip_gen_bitlen = function(desc) { // the tree descriptor
20210 var tree = desc.dyn_tree;
20211 var extra = desc.extra_bits;
20212 var base = desc.extra_base;
20213 var max_code = desc.max_code;
20214 var max_length = desc.max_length;
20215 var stree = desc.static_tree;
20216 var h; // heap index
20217 var n, m; // iterate over the tree elements
20218 var bits; // bit length
20219 var xbits; // extra bits
20220 var f; // frequency
20221 var overflow = 0; // number of elements with bit length too large
20222
20223 for(bits = 0; bits <= zip_MAX_BITS; bits++)
20224 zip_bl_count[bits] = 0;
20225
20226 /* In a first pass, compute the optimal bit lengths (which may
20227 * overflow in the case of the bit length tree).
20228 */
20229 tree[zip_heap[zip_heap_max]].dl = 0; // root of the heap
20230
20231 for(h = zip_heap_max + 1; h < zip_HEAP_SIZE; h++) {
20232 n = zip_heap[h];
20233 bits = tree[tree[n].dl].dl + 1;
20234 if(bits > max_length) {
20235 bits = max_length;
20236 overflow++;
20237 }
20238 tree[n].dl = bits;
20239 // We overwrite tree[n].dl which is no longer needed
20240
20241 if(n > max_code)
20242 continue; // not a leaf node
20243
20244 zip_bl_count[bits]++;
20245 xbits = 0;
20246 if(n >= base)
20247 xbits = extra[n - base];
20248 f = tree[n].fc;
20249 zip_opt_len += f * (bits + xbits);
20250 if(stree != null)
20251 zip_static_len += f * (stree[n].dl + xbits);
20252 }
20253 if(overflow == 0)
20254 return;
20255
20256 // This happens for example on obj2 and pic of the Calgary corpus
20257
20258 // Find the first bit length which could increase:
20259 do {
20260 bits = max_length - 1;
20261 while(zip_bl_count[bits] == 0)
20262 bits--;
20263 zip_bl_count[bits]--; // move one leaf down the tree
20264 zip_bl_count[bits + 1] += 2; // move one overflow item as its brother
20265 zip_bl_count[max_length]--;
20266 /* The brother of the overflow item also moves one step up,
20267 * but this does not affect bl_count[max_length]
20268 */
20269 overflow -= 2;
20270 } while(overflow > 0);
20271
20272 /* Now recompute all bit lengths, scanning in increasing frequency.
20273 * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
20274 * lengths instead of fixing only the wrong ones. This idea is taken
20275 * from 'ar' written by Haruhiko Okumura.)
20276 */
20277 for(bits = max_length; bits != 0; bits--) {
20278 n = zip_bl_count[bits];
20279 while(n != 0) {
20280 m = zip_heap[--h];
20281 if(m > max_code)
20282 continue;
20283 if(tree[m].dl != bits) {
20284 zip_opt_len += (bits - tree[m].dl) * tree[m].fc;
20285 tree[m].fc = bits;
20286 }
20287 n--;
20288 }
20289 }
20290 }
20291
20292 /* ==========================================================================
20293 * Generate the codes for a given tree and bit counts (which need not be
20294 * optimal).
20295 * IN assertion: the array bl_count contains the bit length statistics for
20296 * the given tree and the field len is set for all tree elements.
20297 * OUT assertion: the field code is set for all tree elements of non
20298 * zero code length.
20299 */
20300 var zip_gen_codes = function(tree, // the tree to decorate
20301 max_code) { // largest code with non zero frequency
20302 var next_code = new Array(zip_MAX_BITS+1); // next code value for each bit length
20303 var code = 0; // running code value
20304 var bits; // bit index
20305 var n; // code index
20306
20307 /* The distribution counts are first used to generate the code values
20308 * without bit reversal.
20309 */
20310 for(bits = 1; bits <= zip_MAX_BITS; bits++) {
20311 code = ((code + zip_bl_count[bits-1]) << 1);
20312 next_code[bits] = code;
20313 }
20314
20315 /* Check that the bit counts in bl_count are consistent. The last code
20316 * must be all ones.
20317 */
20318 // Assert (code + encoder->bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
20319 // "inconsistent bit counts");
20320 // Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
20321
20322 for(n = 0; n <= max_code; n++) {
20323 var len = tree[n].dl;
20324 if(len == 0)
20325 continue;
20326 // Now reverse the bits
20327 tree[n].fc = zip_bi_reverse(next_code[len]++, len);
20328
20329 // Tracec(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
20330 // n, (isgraph(n) ? n : ' '), len, tree[n].fc, next_code[len]-1));
20331 }
20332 }
20333
20334 /* ==========================================================================
20335 * Construct one Huffman tree and assigns the code bit strings and lengths.
20336 * Update the total bit length for the current block.
20337 * IN assertion: the field freq is set for all tree elements.
20338 * OUT assertions: the fields len and code are set to the optimal bit length
20339 * and corresponding code. The length opt_len is updated; static_len is
20340 * also updated if stree is not null. The field max_code is set.
20341 */
20342 var zip_build_tree = function(desc) { // the tree descriptor
20343 var tree = desc.dyn_tree;
20344 var stree = desc.static_tree;
20345 var elems = desc.elems;
20346 var n, m; // iterate over heap elements
20347 var max_code = -1; // largest code with non zero frequency
20348 var node = elems; // next internal node of the tree
20349
20350 /* Construct the initial heap, with least frequent element in
20351 * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
20352 * heap[0] is not used.
20353 */
20354 zip_heap_len = 0;
20355 zip_heap_max = zip_HEAP_SIZE;
20356
20357 for(n = 0; n < elems; n++) {
20358 if(tree[n].fc != 0) {
20359 zip_heap[++zip_heap_len] = max_code = n;
20360 zip_depth[n] = 0;
20361 } else
20362 tree[n].dl = 0;
20363 }
20364
20365 /* The pkzip format requires that at least one distance code exists,
20366 * and that at least one bit should be sent even if there is only one
20367 * possible code. So to avoid special checks later on we force at least
20368 * two codes of non zero frequency.
20369 */
20370 while(zip_heap_len < 2) {
20371 var xnew = zip_heap[++zip_heap_len] = (max_code < 2 ? ++max_code : 0);
20372 tree[xnew].fc = 1;
20373 zip_depth[xnew] = 0;
20374 zip_opt_len--;
20375 if(stree != null)
20376 zip_static_len -= stree[xnew].dl;
20377 // new is 0 or 1 so it does not have extra bits
20378 }
20379 desc.max_code = max_code;
20380
20381 /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
20382 * establish sub-heaps of increasing lengths:
20383 */
20384 for(n = zip_heap_len >> 1; n >= 1; n--)
20385 zip_pqdownheap(tree, n);
20386
20387 /* Construct the Huffman tree by repeatedly combining the least two
20388 * frequent nodes.
20389 */
20390 do {
20391 n = zip_heap[zip_SMALLEST];
20392 zip_heap[zip_SMALLEST] = zip_heap[zip_heap_len--];
20393 zip_pqdownheap(tree, zip_SMALLEST);
20394
20395 m = zip_heap[zip_SMALLEST]; // m = node of next least frequency
20396
20397 // keep the nodes sorted by frequency
20398 zip_heap[--zip_heap_max] = n;
20399 zip_heap[--zip_heap_max] = m;
20400
20401 // Create a new node father of n and m
20402 tree[node].fc = tree[n].fc + tree[m].fc;
20403 // depth[node] = (char)(MAX(depth[n], depth[m]) + 1);
20404 if(zip_depth[n] > zip_depth[m] + 1)
20405 zip_depth[node] = zip_depth[n];
20406 else
20407 zip_depth[node] = zip_depth[m] + 1;
20408 tree[n].dl = tree[m].dl = node;
20409
20410 // and insert the new node in the heap
20411 zip_heap[zip_SMALLEST] = node++;
20412 zip_pqdownheap(tree, zip_SMALLEST);
20413
20414 } while(zip_heap_len >= 2);
20415
20416 zip_heap[--zip_heap_max] = zip_heap[zip_SMALLEST];
20417
20418 /* At this point, the fields freq and dad are set. We can now
20419 * generate the bit lengths.
20420 */
20421 zip_gen_bitlen(desc);
20422
20423 // The field len is now set, we can generate the bit codes
20424 zip_gen_codes(tree, max_code);
20425 }
20426
20427 /* ==========================================================================
20428 * Scan a literal or distance tree to determine the frequencies of the codes
20429 * in the bit length tree. Updates opt_len to take into account the repeat
20430 * counts. (The contribution of the bit length codes will be added later
20431 * during the construction of bl_tree.)
20432 */
20433 var zip_scan_tree = function(tree,// the tree to be scanned
20434 max_code) { // and its largest code of non zero frequency
20435 var n; // iterates over all tree elements
20436 var prevlen = -1; // last emitted length
20437 var curlen; // length of current code
20438 var nextlen = tree[0].dl; // length of next code
20439 var count = 0; // repeat count of the current code
20440 var max_count = 7; // max repeat count
20441 var min_count = 4; // min repeat count
20442
20443 if(nextlen == 0) {
20444 max_count = 138;
20445 min_count = 3;
20446 }
20447 tree[max_code + 1].dl = 0xffff; // guard
20448
20449 for(n = 0; n <= max_code; n++) {
20450 curlen = nextlen;
20451 nextlen = tree[n + 1].dl;
20452 if(++count < max_count && curlen == nextlen)
20453 continue;
20454 else if(count < min_count)
20455 zip_bl_tree[curlen].fc += count;
20456 else if(curlen != 0) {
20457 if(curlen != prevlen)
20458 zip_bl_tree[curlen].fc++;
20459 zip_bl_tree[zip_REP_3_6].fc++;
20460 } else if(count <= 10)
20461 zip_bl_tree[zip_REPZ_3_10].fc++;
20462 else
20463 zip_bl_tree[zip_REPZ_11_138].fc++;
20464 count = 0; prevlen = curlen;
20465 if(nextlen == 0) {
20466 max_count = 138;
20467 min_count = 3;
20468 } else if(curlen == nextlen) {
20469 max_count = 6;
20470 min_count = 3;
20471 } else {
20472 max_count = 7;
20473 min_count = 4;
20474 }
20475 }
20476 }
20477
20478 /* ==========================================================================
20479 * Send a literal or distance tree in compressed form, using the codes in
20480 * bl_tree.
20481 */
20482 var zip_send_tree = function(tree, // the tree to be scanned
20483 max_code) { // and its largest code of non zero frequency
20484 var n; // iterates over all tree elements
20485 var prevlen = -1; // last emitted length
20486 var curlen; // length of current code
20487 var nextlen = tree[0].dl; // length of next code
20488 var count = 0; // repeat count of the current code
20489 var max_count = 7; // max repeat count
20490 var min_count = 4; // min repeat count
20491
20492 /* tree[max_code+1].dl = -1; */ /* guard already set */
20493 if(nextlen == 0) {
20494 max_count = 138;
20495 min_count = 3;
20496 }
20497
20498 for(n = 0; n <= max_code; n++) {
20499 curlen = nextlen;
20500 nextlen = tree[n+1].dl;
20501 if(++count < max_count && curlen == nextlen) {
20502 continue;
20503 } else if(count < min_count) {
20504 do { zip_SEND_CODE(curlen, zip_bl_tree); } while(--count != 0);
20505 } else if(curlen != 0) {
20506 if(curlen != prevlen) {
20507 zip_SEND_CODE(curlen, zip_bl_tree);
20508 count--;
20509 }
20510 // Assert(count >= 3 && count <= 6, " 3_6?");
20511 zip_SEND_CODE(zip_REP_3_6, zip_bl_tree);
20512 zip_send_bits(count - 3, 2);
20513 } else if(count <= 10) {
20514 zip_SEND_CODE(zip_REPZ_3_10, zip_bl_tree);
20515 zip_send_bits(count-3, 3);
20516 } else {
20517 zip_SEND_CODE(zip_REPZ_11_138, zip_bl_tree);
20518 zip_send_bits(count-11, 7);
20519 }
20520 count = 0;
20521 prevlen = curlen;
20522 if(nextlen == 0) {
20523 max_count = 138;
20524 min_count = 3;
20525 } else if(curlen == nextlen) {
20526 max_count = 6;
20527 min_count = 3;
20528 } else {
20529 max_count = 7;
20530 min_count = 4;
20531 }
20532 }
20533 }
20534
20535 /* ==========================================================================
20536 * Construct the Huffman tree for the bit lengths and return the index in
20537 * bl_order of the last bit length code to send.
20538 */
20539 var zip_build_bl_tree = function() {
20540 var max_blindex; // index of last bit length code of non zero freq
20541
20542 // Determine the bit length frequencies for literal and distance trees
20543 zip_scan_tree(zip_dyn_ltree, zip_l_desc.max_code);
20544 zip_scan_tree(zip_dyn_dtree, zip_d_desc.max_code);
20545
20546 // Build the bit length tree:
20547 zip_build_tree(zip_bl_desc);
20548 /* opt_len now includes the length of the tree representations, except
20549 * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
20550 */
20551
20552 /* Determine the number of bit length codes to send. The pkzip format
20553 * requires that at least 4 bit length codes be sent. (appnote.txt says
20554 * 3 but the actual value used is 4.)
20555 */
20556 for(max_blindex = zip_BL_CODES-1; max_blindex >= 3; max_blindex--) {
20557 if(zip_bl_tree[zip_bl_order[max_blindex]].dl != 0) break;
20558 }
20559 /* Update opt_len to include the bit length tree and counts */
20560 zip_opt_len += 3*(max_blindex+1) + 5+5+4;
20561 // Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
20562 // encoder->opt_len, encoder->static_len));
20563
20564 return max_blindex;
20565 }
20566
20567 /* ==========================================================================
20568 * Send the header for a block using dynamic Huffman trees: the counts, the
20569 * lengths of the bit length codes, the literal tree and the distance tree.
20570 * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
20571 */
20572 var zip_send_all_trees = function(lcodes, dcodes, blcodes) { // number of codes for each tree
20573 var rank; // index in bl_order
20574
20575 // Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
20576 // Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
20577 // "too many codes");
20578 // Tracev((stderr, "\nbl counts: "));
20579 zip_send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt
20580 zip_send_bits(dcodes-1, 5);
20581 zip_send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt
20582 for(rank = 0; rank < blcodes; rank++) {
20583 // Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
20584 zip_send_bits(zip_bl_tree[zip_bl_order[rank]].dl, 3);
20585 }
20586
20587 // send the literal tree
20588 zip_send_tree(zip_dyn_ltree,lcodes-1);
20589
20590 // send the distance tree
20591 zip_send_tree(zip_dyn_dtree,dcodes-1);
20592 }
20593
20594 /* ==========================================================================
20595 * Determine the best encoding for the current block: dynamic trees, static
20596 * trees or store, and output the encoded block to the zip file.
20597 */
20598 var zip_flush_block = function(eof) { // true if this is the last block for a file
20599 var opt_lenb, static_lenb; // opt_len and static_len in bytes
20600 var max_blindex; // index of last bit length code of non zero freq
20601 var stored_len; // length of input block
20602
20603 stored_len = zip_strstart - zip_block_start;
20604 zip_flag_buf[zip_last_flags] = zip_flags; // Save the flags for the last 8 items
20605
20606 // Construct the literal and distance trees
20607 zip_build_tree(zip_l_desc);
20608 // Tracev((stderr, "\nlit data: dyn %ld, stat %ld",
20609 // encoder->opt_len, encoder->static_len));
20610
20611 zip_build_tree(zip_d_desc);
20612 // Tracev((stderr, "\ndist data: dyn %ld, stat %ld",
20613 // encoder->opt_len, encoder->static_len));
20614 /* At this point, opt_len and static_len are the total bit lengths of
20615 * the compressed block data, excluding the tree representations.
20616 */
20617
20618 /* Build the bit length tree for the above two trees, and get the index
20619 * in bl_order of the last bit length code to send.
20620 */
20621 max_blindex = zip_build_bl_tree();
20622
20623 // Determine the best encoding. Compute first the block length in bytes
20624 opt_lenb = (zip_opt_len +3+7)>>3;
20625 static_lenb = (zip_static_len+3+7)>>3;
20626
20627 // Trace((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ",
20628 // opt_lenb, encoder->opt_len,
20629 // static_lenb, encoder->static_len, stored_len,
20630 // encoder->last_lit, encoder->last_dist));
20631
20632 if(static_lenb <= opt_lenb)
20633 opt_lenb = static_lenb;
20634 if(stored_len + 4 <= opt_lenb // 4: two words for the lengths
20635 && zip_block_start >= 0) {
20636 var i;
20637
20638 /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
20639 * Otherwise we can't have processed more than WSIZE input bytes since
20640 * the last block flush, because compression would have been
20641 * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
20642 * transform a block into a stored block.
20643 */
20644 zip_send_bits((zip_STORED_BLOCK<<1)+eof, 3); /* send block type */
20645 zip_bi_windup(); /* align on byte boundary */
20646 zip_put_short(stored_len);
20647 zip_put_short(~stored_len);
20648
20649 // copy block
20650 /*
20651 p = &window[block_start];
20652 for(i = 0; i < stored_len; i++)
20653 put_byte(p[i]);
20654 */
20655 for(i = 0; i < stored_len; i++)
20656 zip_put_byte(zip_window[zip_block_start + i]);
20657
20658 } else if(static_lenb == opt_lenb) {
20659 zip_send_bits((zip_STATIC_TREES<<1)+eof, 3);
20660 zip_compress_block(zip_static_ltree, zip_static_dtree);
20661 } else {
20662 zip_send_bits((zip_DYN_TREES<<1)+eof, 3);
20663 zip_send_all_trees(zip_l_desc.max_code+1,
20664 zip_d_desc.max_code+1,
20665 max_blindex+1);
20666 zip_compress_block(zip_dyn_ltree, zip_dyn_dtree);
20667 }
20668
20669 zip_init_block();
20670
20671 if(eof != 0)
20672 zip_bi_windup();
20673 }
20674
20675 /* ==========================================================================
20676 * Save the match info and tally the frequency counts. Return true if
20677 * the current block must be flushed.
20678 */
20679 var zip_ct_tally = function(
20680 dist, // distance of matched string
20681 lc) { // match length-MIN_MATCH or unmatched char (if dist==0)
20682 zip_l_buf[zip_last_lit++] = lc;
20683 if(dist == 0) {
20684 // lc is the unmatched char
20685 zip_dyn_ltree[lc].fc++;
20686 } else {
20687 // Here, lc is the match length - MIN_MATCH
20688 dist--; // dist = match distance - 1
20689 // Assert((ush)dist < (ush)MAX_DIST &&
20690 // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
20691 // (ush)D_CODE(dist) < (ush)D_CODES, "ct_tally: bad match");
20692
20693 zip_dyn_ltree[zip_length_code[lc]+zip_LITERALS+1].fc++;
20694 zip_dyn_dtree[zip_D_CODE(dist)].fc++;
20695
20696 zip_d_buf[zip_last_dist++] = dist;
20697 zip_flags |= zip_flag_bit;
20698 }
20699 zip_flag_bit <<= 1;
20700
20701 // Output the flags if they fill a byte
20702 if((zip_last_lit & 7) == 0) {
20703 zip_flag_buf[zip_last_flags++] = zip_flags;
20704 zip_flags = 0;
20705 zip_flag_bit = 1;
20706 }
20707 // Try to guess if it is profitable to stop the current block here
20708 if(zip_compr_level > 2 && (zip_last_lit & 0xfff) == 0) {
20709 // Compute an upper bound for the compressed length
20710 var out_length = zip_last_lit * 8;
20711 var in_length = zip_strstart - zip_block_start;
20712 var dcode;
20713
20714 for(dcode = 0; dcode < zip_D_CODES; dcode++) {
20715 out_length += zip_dyn_dtree[dcode].fc * (5 + zip_extra_dbits[dcode]);
20716 }
20717 out_length >>= 3;
20718 // Trace((stderr,"\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ",
20719 // encoder->last_lit, encoder->last_dist, in_length, out_length,
20720 // 100L - out_length*100L/in_length));
20721 if(zip_last_dist < parseInt(zip_last_lit/2) &&
20722 out_length < parseInt(in_length/2))
20723 return true;
20724 }
20725 return (zip_last_lit == zip_LIT_BUFSIZE-1 ||
20726 zip_last_dist == zip_DIST_BUFSIZE);
20727 /* We avoid equality with LIT_BUFSIZE because of wraparound at 64K
20728 * on 16 bit machines and because stored blocks are restricted to
20729 * 64K-1 bytes.
20730 */
20731 }
20732
20733 /* ==========================================================================
20734 * Send the block data compressed using the given Huffman trees
20735 */
20736 var zip_compress_block = function(
20737 ltree, // literal tree
20738 dtree) { // distance tree
20739 var dist; // distance of matched string
20740 var lc; // match length or unmatched char (if dist == 0)
20741 var lx = 0; // running index in l_buf
20742 var dx = 0; // running index in d_buf
20743 var fx = 0; // running index in flag_buf
20744 var flag = 0; // current flags
20745 var code; // the code to send
20746 var extra; // number of extra bits to send
20747
20748 if(zip_last_lit != 0) do {
20749 if((lx & 7) == 0)
20750 flag = zip_flag_buf[fx++];
20751 lc = zip_l_buf[lx++] & 0xff;
20752 if((flag & 1) == 0) {
20753 zip_SEND_CODE(lc, ltree); /* send a literal byte */
20754 // Tracecv(isgraph(lc), (stderr," '%c' ", lc));
20755 } else {
20756 // Here, lc is the match length - MIN_MATCH
20757 code = zip_length_code[lc];
20758 zip_SEND_CODE(code+zip_LITERALS+1, ltree); // send the length code
20759 extra = zip_extra_lbits[code];
20760 if(extra != 0) {
20761 lc -= zip_base_length[code];
20762 zip_send_bits(lc, extra); // send the extra length bits
20763 }
20764 dist = zip_d_buf[dx++];
20765 // Here, dist is the match distance - 1
20766 code = zip_D_CODE(dist);
20767 // Assert (code < D_CODES, "bad d_code");
20768
20769 zip_SEND_CODE(code, dtree); // send the distance code
20770 extra = zip_extra_dbits[code];
20771 if(extra != 0) {
20772 dist -= zip_base_dist[code];
20773 zip_send_bits(dist, extra); // send the extra distance bits
20774 }
20775 } // literal or match pair ?
20776 flag >>= 1;
20777 } while(lx < zip_last_lit);
20778
20779 zip_SEND_CODE(zip_END_BLOCK, ltree);
20780 }
20781
20782 /* ==========================================================================
20783 * Send a value on a given number of bits.
20784 * IN assertion: length <= 16 and value fits in length bits.
20785 */
20786 var zip_Buf_size = 16; // bit size of bi_buf
20787 var zip_send_bits = function(
20788 value, // value to send
20789 length) { // number of bits
20790 /* If not enough room in bi_buf, use (valid) bits from bi_buf and
20791 * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
20792 * unused bits in value.
20793 */
20794 if(zip_bi_valid > zip_Buf_size - length) {
20795 zip_bi_buf |= (value << zip_bi_valid);
20796 zip_put_short(zip_bi_buf);
20797 zip_bi_buf = (value >> (zip_Buf_size - zip_bi_valid));
20798 zip_bi_valid += length - zip_Buf_size;
20799 } else {
20800 zip_bi_buf |= value << zip_bi_valid;
20801 zip_bi_valid += length;
20802 }
20803 }
20804
20805 /* ==========================================================================
20806 * Reverse the first len bits of a code, using straightforward code (a faster
20807 * method would use a table)
20808 * IN assertion: 1 <= len <= 15
20809 */
20810 var zip_bi_reverse = function(
20811 code, // the value to invert
20812 len) { // its bit length
20813 var res = 0;
20814 do {
20815 res |= code & 1;
20816 code >>= 1;
20817 res <<= 1;
20818 } while(--len > 0);
20819 return res >> 1;
20820 }
20821
20822 /* ==========================================================================
20823 * Write out any remaining bits in an incomplete byte.
20824 */
20825 var zip_bi_windup = function() {
20826 if(zip_bi_valid > 8) {
20827 zip_put_short(zip_bi_buf);
20828 } else if(zip_bi_valid > 0) {
20829 zip_put_byte(zip_bi_buf);
20830 }
20831 zip_bi_buf = 0;
20832 zip_bi_valid = 0;
20833 }
20834
20835 var zip_qoutbuf = function() {
20836 if(zip_outcnt != 0) {
20837 var q, i;
20838 q = zip_new_queue();
20839 if(zip_qhead == null)
20840 zip_qhead = zip_qtail = q;
20841 else
20842 zip_qtail = zip_qtail.next = q;
20843 q.len = zip_outcnt - zip_outoff;
20844 // System.arraycopy(zip_outbuf, zip_outoff, q.ptr, 0, q.len);
20845 for(i = 0; i < q.len; i++)
20846 q.ptr[i] = zip_outbuf[zip_outoff + i];
20847 zip_outcnt = zip_outoff = 0;
20848 }
20849 }
20850
20851 var zip_deflate = function(str, level) {
20852 var i, j;
20853
20854 zip_deflate_data = str;
20855 zip_deflate_pos = 0;
20856 if(typeof level == "undefined")
20857 level = zip_DEFAULT_LEVEL;
20858 zip_deflate_start(level);
20859
20860 var buff = new Array(1024);
20861 var aout = [];
20862 while((i = zip_deflate_internal(buff, 0, buff.length)) > 0) {
20863 var cbuf = new Array(i);
20864 for(j = 0; j < i; j++){
20865 cbuf[j] = String.fromCharCode(buff[j]);
20866 }
20867 aout[aout.length] = cbuf.join("");
20868 }
20869 zip_deflate_data = null; // G.C.
20870 return aout.join("");
20871 }
20872
20873 //
20874 // end of the script of Masanao Izumo.
20875 //
20876
20877 // we add the compression method for JSZip
20878 if(!JSZip.compressions["DEFLATE"]) {
20879 JSZip.compressions["DEFLATE"] = {
20880 magic : "\x08\x00",
20881 compress : zip_deflate
20882 }
20883 } else {
20884 JSZip.compressions["DEFLATE"].compress = zip_deflate;
20885 }
20886
20887 })();
20888
20889 // enforcing Stuk's coding style
20890 // vim: set shiftwidth=3 softtabstop=3:
20891 /*
20892 * Port of a script by Masanao Izumo.
20893 *
20894 * Only changes : wrap all the variables in a function and add the
20895 * main function to JSZip (DEFLATE compression method).
20896 * Everything else was written by M. Izumo.
20897 *
20898 * Original code can be found here: http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt
20899 */
20900
20901 if(!JSZip) {
20902 throw "JSZip not defined";
20903 }
20904
20905 /*
20906 * Original:
20907 * http://www.onicos.com/staff/iz/amuse/javascript/expert/inflate.txt
20908 */
20909
20910 (function(){
20911 // the original implementation leaks a global variable.
20912 // Defining the variable here doesn't break anything.
20913 var zip_fixed_bd;
20914
20915 /* Copyright (C) 1999 Masanao Izumo <iz@onicos.co.jp>
20916 * Version: 1.0.0.1
20917 * LastModified: Dec 25 1999
20918 */
20919
20920 /* Interface:
20921 * data = zip_inflate(src);
20922 */
20923
20924 /* constant parameters */
20925 var zip_WSIZE = 32768; // Sliding Window size
20926 var zip_STORED_BLOCK = 0;
20927 var zip_STATIC_TREES = 1;
20928 var zip_DYN_TREES = 2;
20929
20930 /* for inflate */
20931 var zip_lbits = 9; // bits in base literal/length lookup table
20932 var zip_dbits = 6; // bits in base distance lookup table
20933 var zip_INBUFSIZ = 32768; // Input buffer size
20934 var zip_INBUF_EXTRA = 64; // Extra buffer
20935
20936 /* variables (inflate) */
20937 var zip_slide;
20938 var zip_wp; // current position in slide
20939 var zip_fixed_tl = null; // inflate static
20940 var zip_fixed_td; // inflate static
20941 var zip_fixed_bl, fixed_bd; // inflate static
20942 var zip_bit_buf; // bit buffer
20943 var zip_bit_len; // bits in bit buffer
20944 var zip_method;
20945 var zip_eof;
20946 var zip_copy_leng;
20947 var zip_copy_dist;
20948 var zip_tl, zip_td; // literal/length and distance decoder tables
20949 var zip_bl, zip_bd; // number of bits decoded by tl and td
20950
20951 var zip_inflate_data;
20952 var zip_inflate_pos;
20953
20954
20955 /* constant tables (inflate) */
20956 var zip_MASK_BITS = new Array(
20957 0x0000,
20958 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
20959 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff);
20960 // Tables for deflate from PKZIP's appnote.txt.
20961 var zip_cplens = new Array( // Copy lengths for literal codes 257..285
20962 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
20963 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0);
20964 /* note: see note #13 above about the 258 in this list. */
20965 var zip_cplext = new Array( // Extra bits for literal codes 257..285
20966 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
20967 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99); // 99==invalid
20968 var zip_cpdist = new Array( // Copy offsets for distance codes 0..29
20969 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
20970 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
20971 8193, 12289, 16385, 24577);
20972 var zip_cpdext = new Array( // Extra bits for distance codes
20973 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
20974 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
20975 12, 12, 13, 13);
20976 var zip_border = new Array( // Order of the bit length code lengths
20977 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15);
20978 /* objects (inflate) */
20979
20980 function zip_HuftList() {
20981 this.next = null;
20982 this.list = null;
20983 }
20984
20985 function zip_HuftNode() {
20986 this.e = 0; // number of extra bits or operation
20987 this.b = 0; // number of bits in this code or subcode
20988
20989 // union
20990 this.n = 0; // literal, length base, or distance base
20991 this.t = null; // (zip_HuftNode) pointer to next level of table
20992 }
20993
20994 function zip_HuftBuild(b, // code lengths in bits (all assumed <= BMAX)
20995 n, // number of codes (assumed <= N_MAX)
20996 s, // number of simple-valued codes (0..s-1)
20997 d, // list of base values for non-simple codes
20998 e, // list of extra bits for non-simple codes
20999 mm // maximum lookup bits
21000 ) {
21001 this.BMAX = 16; // maximum bit length of any code
21002 this.N_MAX = 288; // maximum number of codes in any set
21003 this.status = 0; // 0: success, 1: incomplete table, 2: bad input
21004 this.root = null; // (zip_HuftList) starting table
21005 this.m = 0; // maximum lookup bits, returns actual
21006
21007 /* Given a list of code lengths and a maximum table size, make a set of
21008 tables to decode that set of codes. Return zero on success, one if
21009 the given code set is incomplete (the tables are still built in this
21010 case), two if the input is invalid (all zero length codes or an
21011 oversubscribed set of lengths), and three if not enough memory.
21012 The code with value 256 is special, and the tables are constructed
21013 so that no bits beyond that code are fetched when that code is
21014 decoded. */
21015 {
21016 var a; // counter for codes of length k
21017 var c = new Array(this.BMAX+1); // bit length count table
21018 var el; // length of EOB code (value 256)
21019 var f; // i repeats in table every f entries
21020 var g; // maximum code length
21021 var h; // table level
21022 var i; // counter, current code
21023 var j; // counter
21024 var k; // number of bits in current code
21025 var lx = new Array(this.BMAX+1); // stack of bits per table
21026 var p; // pointer into c[], b[], or v[]
21027 var pidx; // index of p
21028 var q; // (zip_HuftNode) points to current table
21029 var r = new zip_HuftNode(); // table entry for structure assignment
21030 var u = new Array(this.BMAX); // zip_HuftNode[BMAX][] table stack
21031 var v = new Array(this.N_MAX); // values in order of bit length
21032 var w;
21033 var x = new Array(this.BMAX+1);// bit offsets, then code stack
21034 var xp; // pointer into x or c
21035 var y; // number of dummy codes added
21036 var z; // number of entries in current table
21037 var o;
21038 var tail; // (zip_HuftList)
21039
21040 tail = this.root = null;
21041 for(i = 0; i < c.length; i++)
21042 c[i] = 0;
21043 for(i = 0; i < lx.length; i++)
21044 lx[i] = 0;
21045 for(i = 0; i < u.length; i++)
21046 u[i] = null;
21047 for(i = 0; i < v.length; i++)
21048 v[i] = 0;
21049 for(i = 0; i < x.length; i++)
21050 x[i] = 0;
21051
21052 // Generate counts for each bit length
21053 el = n > 256 ? b[256] : this.BMAX; // set length of EOB code, if any
21054 p = b; pidx = 0;
21055 i = n;
21056 do {
21057 c[p[pidx]]++; // assume all entries <= BMAX
21058 pidx++;
21059 } while(--i > 0);
21060 if(c[0] == n) { // null input--all zero length codes
21061 this.root = null;
21062 this.m = 0;
21063 this.status = 0;
21064 return;
21065 }
21066
21067 // Find minimum and maximum length, bound *m by those
21068 for(j = 1; j <= this.BMAX; j++)
21069 if(c[j] != 0)
21070 break;
21071 k = j; // minimum code length
21072 if(mm < j)
21073 mm = j;
21074 for(i = this.BMAX; i != 0; i--)
21075 if(c[i] != 0)
21076 break;
21077 g = i; // maximum code length
21078 if(mm > i)
21079 mm = i;
21080
21081 // Adjust last length count to fill out codes, if needed
21082 for(y = 1 << j; j < i; j++, y <<= 1)
21083 if((y -= c[j]) < 0) {
21084 this.status = 2; // bad input: more codes than bits
21085 this.m = mm;
21086 return;
21087 }
21088 if((y -= c[i]) < 0) {
21089 this.status = 2;
21090 this.m = mm;
21091 return;
21092 }
21093 c[i] += y;
21094
21095 // Generate starting offsets into the value table for each length
21096 x[1] = j = 0;
21097 p = c;
21098 pidx = 1;
21099 xp = 2;
21100 while(--i > 0) // note that i == g from above
21101 x[xp++] = (j += p[pidx++]);
21102
21103 // Make a table of values in order of bit lengths
21104 p = b; pidx = 0;
21105 i = 0;
21106 do {
21107 if((j = p[pidx++]) != 0)
21108 v[x[j]++] = i;
21109 } while(++i < n);
21110 n = x[g]; // set n to length of v
21111
21112 // Generate the Huffman codes and for each, make the table entries
21113 x[0] = i = 0; // first Huffman code is zero
21114 p = v; pidx = 0; // grab values in bit order
21115 h = -1; // no tables yet--level -1
21116 w = lx[0] = 0; // no bits decoded yet
21117 q = null; // ditto
21118 z = 0; // ditto
21119
21120 // go through the bit lengths (k already is bits in shortest code)
21121 for(; k <= g; k++) {
21122 a = c[k];
21123 while(a-- > 0) {
21124 // here i is the Huffman code of length k bits for value p[pidx]
21125 // make tables up to required level
21126 while(k > w + lx[1 + h]) {
21127 w += lx[1 + h]; // add bits already decoded
21128 h++;
21129
21130 // compute minimum size table less than or equal to *m bits
21131 z = (z = g - w) > mm ? mm : z; // upper limit
21132 if((f = 1 << (j = k - w)) > a + 1) { // try a k-w bit table
21133 // too few codes for k-w bit table
21134 f -= a + 1; // deduct codes from patterns left
21135 xp = k;
21136 while(++j < z) { // try smaller tables up to z bits
21137 if((f <<= 1) <= c[++xp])
21138 break; // enough codes to use up j bits
21139 f -= c[xp]; // else deduct codes from patterns
21140 }
21141 }
21142 if(w + j > el && w < el)
21143 j = el - w; // make EOB code end at table
21144 z = 1 << j; // table entries for j-bit table
21145 lx[1 + h] = j; // set table size in stack
21146
21147 // allocate and link in new table
21148 q = new Array(z);
21149 for(o = 0; o < z; o++) {
21150 q[o] = new zip_HuftNode();
21151 }
21152
21153 if(tail == null)
21154 tail = this.root = new zip_HuftList();
21155 else
21156 tail = tail.next = new zip_HuftList();
21157 tail.next = null;
21158 tail.list = q;
21159 u[h] = q; // table starts after link
21160
21161 /* connect to last table, if there is one */
21162 if(h > 0) {
21163 x[h] = i; // save pattern for backing up
21164 r.b = lx[h]; // bits to dump before this table
21165 r.e = 16 + j; // bits in this table
21166 r.t = q; // pointer to this table
21167 j = (i & ((1 << w) - 1)) >> (w - lx[h]);
21168 u[h-1][j].e = r.e;
21169 u[h-1][j].b = r.b;
21170 u[h-1][j].n = r.n;
21171 u[h-1][j].t = r.t;
21172 }
21173 }
21174
21175 // set up table entry in r
21176 r.b = k - w;
21177 if(pidx >= n)
21178 r.e = 99; // out of values--invalid code
21179 else if(p[pidx] < s) {
21180 r.e = (p[pidx] < 256 ? 16 : 15); // 256 is end-of-block code
21181 r.n = p[pidx++]; // simple code is just the value
21182 } else {
21183 r.e = e[p[pidx] - s]; // non-simple--look up in lists
21184 r.n = d[p[pidx++] - s];
21185 }
21186
21187 // fill code-like entries with r //
21188 f = 1 << (k - w);
21189 for(j = i >> w; j < z; j += f) {
21190 q[j].e = r.e;
21191 q[j].b = r.b;
21192 q[j].n = r.n;
21193 q[j].t = r.t;
21194 }
21195
21196 // backwards increment the k-bit code i
21197 for(j = 1 << (k - 1); (i & j) != 0; j >>= 1)
21198 i ^= j;
21199 i ^= j;
21200
21201 // backup over finished tables
21202 while((i & ((1 << w) - 1)) != x[h]) {
21203 w -= lx[h]; // don't need to update q
21204 h--;
21205 }
21206 }
21207 }
21208
21209 /* return actual size of base table */
21210 this.m = lx[1];
21211
21212 /* Return true (1) if we were given an incomplete table */
21213 this.status = ((y != 0 && g != 1) ? 1 : 0);
21214 } /* end of constructor */
21215 }
21216
21217
21218 /* routines (inflate) */
21219
21220 function zip_GET_BYTE() {
21221 if(zip_inflate_data.length == zip_inflate_pos)
21222 return -1;
21223 return zip_inflate_data.charCodeAt(zip_inflate_pos++) & 0xff;
21224 }
21225
21226 function zip_NEEDBITS(n) {
21227 while(zip_bit_len < n) {
21228 zip_bit_buf |= zip_GET_BYTE() << zip_bit_len;
21229 zip_bit_len += 8;
21230 }
21231 }
21232
21233 function zip_GETBITS(n) {
21234 return zip_bit_buf & zip_MASK_BITS[n];
21235 }
21236
21237 function zip_DUMPBITS(n) {
21238 zip_bit_buf >>= n;
21239 zip_bit_len -= n;
21240 }
21241
21242 function zip_inflate_codes(buff, off, size) {
21243 /* inflate (decompress) the codes in a deflated (compressed) block.
21244 Return an error code or zero if it all goes ok. */
21245 var e; // table entry flag/number of extra bits
21246 var t; // (zip_HuftNode) pointer to table entry
21247 var n;
21248
21249 if(size == 0)
21250 return 0;
21251
21252 // inflate the coded data
21253 n = 0;
21254 for(;;) { // do until end of block
21255 zip_NEEDBITS(zip_bl);
21256 t = zip_tl.list[zip_GETBITS(zip_bl)];
21257 e = t.e;
21258 while(e > 16) {
21259 if(e == 99)
21260 return -1;
21261 zip_DUMPBITS(t.b);
21262 e -= 16;
21263 zip_NEEDBITS(e);
21264 t = t.t[zip_GETBITS(e)];
21265 e = t.e;
21266 }
21267 zip_DUMPBITS(t.b);
21268
21269 if(e == 16) { // then it's a literal
21270 zip_wp &= zip_WSIZE - 1;
21271 buff[off + n++] = zip_slide[zip_wp++] = t.n;
21272 if(n == size)
21273 return size;
21274 continue;
21275 }
21276
21277 // exit if end of block
21278 if(e == 15)
21279 break;
21280
21281 // it's an EOB or a length
21282
21283 // get length of block to copy
21284 zip_NEEDBITS(e);
21285 zip_copy_leng = t.n + zip_GETBITS(e);
21286 zip_DUMPBITS(e);
21287
21288 // decode distance of block to copy
21289 zip_NEEDBITS(zip_bd);
21290 t = zip_td.list[zip_GETBITS(zip_bd)];
21291 e = t.e;
21292
21293 while(e > 16) {
21294 if(e == 99)
21295 return -1;
21296 zip_DUMPBITS(t.b);
21297 e -= 16;
21298 zip_NEEDBITS(e);
21299 t = t.t[zip_GETBITS(e)];
21300 e = t.e;
21301 }
21302 zip_DUMPBITS(t.b);
21303 zip_NEEDBITS(e);
21304 zip_copy_dist = zip_wp - t.n - zip_GETBITS(e);
21305 zip_DUMPBITS(e);
21306
21307 // do the copy
21308 while(zip_copy_leng > 0 && n < size) {
21309 zip_copy_leng--;
21310 zip_copy_dist &= zip_WSIZE - 1;
21311 zip_wp &= zip_WSIZE - 1;
21312 buff[off + n++] = zip_slide[zip_wp++]
21313 = zip_slide[zip_copy_dist++];
21314 }
21315
21316 if(n == size)
21317 return size;
21318 }
21319
21320 zip_method = -1; // done
21321 return n;
21322 }
21323
21324 function zip_inflate_stored(buff, off, size) {
21325 /* "decompress" an inflated type 0 (stored) block. */
21326 var n;
21327
21328 // go to byte boundary
21329 n = zip_bit_len & 7;
21330 zip_DUMPBITS(n);
21331
21332 // get the length and its complement
21333 zip_NEEDBITS(16);
21334 n = zip_GETBITS(16);
21335 zip_DUMPBITS(16);
21336 zip_NEEDBITS(16);
21337 if(n != ((~zip_bit_buf) & 0xffff))
21338 return -1; // error in compressed data
21339 zip_DUMPBITS(16);
21340
21341 // read and output the compressed data
21342 zip_copy_leng = n;
21343
21344 n = 0;
21345 while(zip_copy_leng > 0 && n < size) {
21346 zip_copy_leng--;
21347 zip_wp &= zip_WSIZE - 1;
21348 zip_NEEDBITS(8);
21349 buff[off + n++] = zip_slide[zip_wp++] =
21350 zip_GETBITS(8);
21351 zip_DUMPBITS(8);
21352 }
21353
21354 if(zip_copy_leng == 0)
21355 zip_method = -1; // done
21356 return n;
21357 }
21358
21359 function zip_inflate_fixed(buff, off, size) {
21360 /* decompress an inflated type 1 (fixed Huffman codes) block. We should
21361 either replace this with a custom decoder, or at least precompute the
21362 Huffman tables. */
21363
21364 // if first time, set up tables for fixed blocks
21365 if(zip_fixed_tl == null) {
21366 var i; // temporary variable
21367 var l = new Array(288); // length list for huft_build
21368 var h; // zip_HuftBuild
21369
21370 // literal table
21371 for(i = 0; i < 144; i++)
21372 l[i] = 8;
21373 for(; i < 256; i++)
21374 l[i] = 9;
21375 for(; i < 280; i++)
21376 l[i] = 7;
21377 for(; i < 288; i++) // make a complete, but wrong code set
21378 l[i] = 8;
21379 zip_fixed_bl = 7;
21380
21381 h = new zip_HuftBuild(l, 288, 257, zip_cplens, zip_cplext,
21382 zip_fixed_bl);
21383 if(h.status != 0) {
21384 alert("HufBuild error: "+h.status);
21385 return -1;
21386 }
21387 zip_fixed_tl = h.root;
21388 zip_fixed_bl = h.m;
21389
21390 // distance table
21391 for(i = 0; i < 30; i++) // make an incomplete code set
21392 l[i] = 5;
21393 zip_fixed_bd = 5;
21394
21395 h = new zip_HuftBuild(l, 30, 0, zip_cpdist, zip_cpdext, zip_fixed_bd);
21396 if(h.status > 1) {
21397 zip_fixed_tl = null;
21398 alert("HufBuild error: "+h.status);
21399 return -1;
21400 }
21401 zip_fixed_td = h.root;
21402 zip_fixed_bd = h.m;
21403 }
21404
21405 zip_tl = zip_fixed_tl;
21406 zip_td = zip_fixed_td;
21407 zip_bl = zip_fixed_bl;
21408 zip_bd = zip_fixed_bd;
21409 return zip_inflate_codes(buff, off, size);
21410 }
21411
21412 function zip_inflate_dynamic(buff, off, size) {
21413 // decompress an inflated type 2 (dynamic Huffman codes) block.
21414 var i; // temporary variables
21415 var j;
21416 var l; // last length
21417 var n; // number of lengths to get
21418 var t; // (zip_HuftNode) literal/length code table
21419 var nb; // number of bit length codes
21420 var nl; // number of literal/length codes
21421 var nd; // number of distance codes
21422 var ll = new Array(286+30); // literal/length and distance code lengths
21423 var h; // (zip_HuftBuild)
21424
21425 for(i = 0; i < ll.length; i++)
21426 ll[i] = 0;
21427
21428 // read in table lengths
21429 zip_NEEDBITS(5);
21430 nl = 257 + zip_GETBITS(5); // number of literal/length codes
21431 zip_DUMPBITS(5);
21432 zip_NEEDBITS(5);
21433 nd = 1 + zip_GETBITS(5); // number of distance codes
21434 zip_DUMPBITS(5);
21435 zip_NEEDBITS(4);
21436 nb = 4 + zip_GETBITS(4); // number of bit length codes
21437 zip_DUMPBITS(4);
21438 if(nl > 286 || nd > 30)
21439 return -1; // bad lengths
21440
21441 // read in bit-length-code lengths
21442 for(j = 0; j < nb; j++)
21443 {
21444 zip_NEEDBITS(3);
21445 ll[zip_border[j]] = zip_GETBITS(3);
21446 zip_DUMPBITS(3);
21447 }
21448 for(; j < 19; j++)
21449 ll[zip_border[j]] = 0;
21450
21451 // build decoding table for trees--single level, 7 bit lookup
21452 zip_bl = 7;
21453 h = new zip_HuftBuild(ll, 19, 19, null, null, zip_bl);
21454 if(h.status != 0)
21455 return -1; // incomplete code set
21456
21457 zip_tl = h.root;
21458 zip_bl = h.m;
21459
21460 // read in literal and distance code lengths
21461 n = nl + nd;
21462 i = l = 0;
21463 while(i < n) {
21464 zip_NEEDBITS(zip_bl);
21465 t = zip_tl.list[zip_GETBITS(zip_bl)];
21466 j = t.b;
21467 zip_DUMPBITS(j);
21468 j = t.n;
21469 if(j < 16) // length of code in bits (0..15)
21470 ll[i++] = l = j; // save last length in l
21471 else if(j == 16) { // repeat last length 3 to 6 times
21472 zip_NEEDBITS(2);
21473 j = 3 + zip_GETBITS(2);
21474 zip_DUMPBITS(2);
21475 if(i + j > n)
21476 return -1;
21477 while(j-- > 0)
21478 ll[i++] = l;
21479 } else if(j == 17) { // 3 to 10 zero length codes
21480 zip_NEEDBITS(3);
21481 j = 3 + zip_GETBITS(3);
21482 zip_DUMPBITS(3);
21483 if(i + j > n)
21484 return -1;
21485 while(j-- > 0)
21486 ll[i++] = 0;
21487 l = 0;
21488 } else { // j == 18: 11 to 138 zero length codes
21489 zip_NEEDBITS(7);
21490 j = 11 + zip_GETBITS(7);
21491 zip_DUMPBITS(7);
21492 if(i + j > n)
21493 return -1;
21494 while(j-- > 0)
21495 ll[i++] = 0;
21496 l = 0;
21497 }
21498 }
21499
21500 // build the decoding tables for literal/length and distance codes
21501 zip_bl = zip_lbits;
21502 h = new zip_HuftBuild(ll, nl, 257, zip_cplens, zip_cplext, zip_bl);
21503 if(zip_bl == 0) // no literals or lengths
21504 h.status = 1;
21505 if(h.status != 0) {
21506 if(h.status == 1)
21507 ;// **incomplete literal tree**
21508 return -1; // incomplete code set
21509 }
21510 zip_tl = h.root;
21511 zip_bl = h.m;
21512
21513 for(i = 0; i < nd; i++)
21514 ll[i] = ll[i + nl];
21515 zip_bd = zip_dbits;
21516 h = new zip_HuftBuild(ll, nd, 0, zip_cpdist, zip_cpdext, zip_bd);
21517 zip_td = h.root;
21518 zip_bd = h.m;
21519
21520 if(zip_bd == 0 && nl > 257) { // lengths but no distances
21521 // **incomplete distance tree**
21522 return -1;
21523 }
21524
21525 if(h.status == 1) {
21526 ;// **incomplete distance tree**
21527 }
21528 if(h.status != 0)
21529 return -1;
21530
21531 // decompress until an end-of-block code
21532 return zip_inflate_codes(buff, off, size);
21533 }
21534
21535 function zip_inflate_start() {
21536 var i;
21537
21538 if(zip_slide == null)
21539 zip_slide = new Array(2 * zip_WSIZE);
21540 zip_wp = 0;
21541 zip_bit_buf = 0;
21542 zip_bit_len = 0;
21543 zip_method = -1;
21544 zip_eof = false;
21545 zip_copy_leng = zip_copy_dist = 0;
21546 zip_tl = null;
21547 }
21548
21549 function zip_inflate_internal(buff, off, size) {
21550 // decompress an inflated entry
21551 var n, i;
21552
21553 n = 0;
21554 while(n < size) {
21555 if(zip_eof && zip_method == -1)
21556 return n;
21557
21558 if(zip_copy_leng > 0) {
21559 if(zip_method != zip_STORED_BLOCK) {
21560 // STATIC_TREES or DYN_TREES
21561 while(zip_copy_leng > 0 && n < size) {
21562 zip_copy_leng--;
21563 zip_copy_dist &= zip_WSIZE - 1;
21564 zip_wp &= zip_WSIZE - 1;
21565 buff[off + n++] = zip_slide[zip_wp++] =
21566 zip_slide[zip_copy_dist++];
21567 }
21568 } else {
21569 while(zip_copy_leng > 0 && n < size) {
21570 zip_copy_leng--;
21571 zip_wp &= zip_WSIZE - 1;
21572 zip_NEEDBITS(8);
21573 buff[off + n++] = zip_slide[zip_wp++] = zip_GETBITS(8);
21574 zip_DUMPBITS(8);
21575 }
21576 if(zip_copy_leng == 0)
21577 zip_method = -1; // done
21578 }
21579 if(n == size)
21580 return n;
21581 }
21582
21583 if(zip_method == -1) {
21584 if(zip_eof)
21585 break;
21586
21587 // read in last block bit
21588 zip_NEEDBITS(1);
21589 if(zip_GETBITS(1) != 0)
21590 zip_eof = true;
21591 zip_DUMPBITS(1);
21592
21593 // read in block type
21594 zip_NEEDBITS(2);
21595 zip_method = zip_GETBITS(2);
21596 zip_DUMPBITS(2);
21597 zip_tl = null;
21598 zip_copy_leng = 0;
21599 }
21600
21601 switch(zip_method) {
21602 case 0: // zip_STORED_BLOCK
21603 i = zip_inflate_stored(buff, off + n, size - n);
21604 break;
21605
21606 case 1: // zip_STATIC_TREES
21607 if(zip_tl != null)
21608 i = zip_inflate_codes(buff, off + n, size - n);
21609 else
21610 i = zip_inflate_fixed(buff, off + n, size - n);
21611 break;
21612
21613 case 2: // zip_DYN_TREES
21614 if(zip_tl != null)
21615 i = zip_inflate_codes(buff, off + n, size - n);
21616 else
21617 i = zip_inflate_dynamic(buff, off + n, size - n);
21618 break;
21619
21620 default: // error
21621 i = -1;
21622 break;
21623 }
21624
21625 if(i == -1) {
21626 if(zip_eof)
21627 return 0;
21628 return -1;
21629 }
21630 n += i;
21631 }
21632 return n;
21633 }
21634
21635 function zip_inflate(str) {
21636 var out, buff;
21637 var i, j;
21638
21639 zip_inflate_start();
21640 zip_inflate_data = str;
21641 zip_inflate_pos = 0;
21642
21643 buff = new Array(1024);
21644 out = "";
21645 while((i = zip_inflate_internal(buff, 0, buff.length)) > 0) {
21646 for(j = 0; j < i; j++)
21647 out += String.fromCharCode(buff[j]);
21648 }
21649 zip_inflate_data = null; // G.C.
21650 return out;
21651 }
21652
21653 //
21654 // end of the script of Masanao Izumo.
21655 //
21656
21657 // we add the compression method for JSZip
21658 if(!JSZip.compressions["DEFLATE"]) {
21659 JSZip.compressions["DEFLATE"] = {
21660 magic : "\x08\x00",
21661 uncompress : zip_inflate
21662 }
21663 } else {
21664 JSZip.compressions["DEFLATE"].uncompress = zip_inflate;
21665 }
21666
21667 })();
21668
21669 // enforcing Stuk's coding style
21670 // vim: set shiftwidth=3 softtabstop=3:
21671 /**
21672
21673 JSZip - A Javascript class for generating and reading zip files
21674 <http://stuartk.com/jszip>
21675
21676 (c) 2011 David Duponchel <d.duponchel@gmail.com>
21677 Dual licenced under the MIT license or GPLv3. See LICENSE.markdown.
21678
21679 **/
21680 /*global JSZip,JSZipBase64 */
21681 (function () {
21682
21683 var MAX_VALUE_16BITS = 65535;
21684 var MAX_VALUE_32BITS = -1; // well, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" is parsed as -1
21685
21686 /**
21687 * Prettify a string read as binary.
21688 * @param {string} str the string to prettify.
21689 * @return {string} a pretty string.
21690 */
21691 var pretty = function (str) {
21692 var res = '', code, i;
21693 for (i = 0; i < (str||"").length; i++) {
21694 code = str.charCodeAt(i);
21695 res += '\\x' + (code < 16 ? "0" : "") + code.toString(16).toUpperCase();
21696 }
21697 return res;
21698 };
21699
21700 /**
21701 * Find a compression registered in JSZip.
21702 * @param {string} compressionMethod the method magic to find.
21703 * @return {Object|null} the JSZip compression object, null if none found.
21704 */
21705 var findCompression = function (compressionMethod) {
21706 for (var method in JSZip.compressions) {
21707 if( !JSZip.compressions.hasOwnProperty(method) ) { continue; }
21708 if (JSZip.compressions[method].magic === compressionMethod) {
21709 return JSZip.compressions[method];
21710 }
21711 }
21712 return null;
21713 };
21714
21715 // class StreamReader {{{
21716 /**
21717 * Read bytes from a stream.
21718 * Developer tip : when debugging, a watch on pretty(this.reader.stream.slice(this.reader.index))
21719 * is very useful :)
21720 * @constructor
21721 * @param {String|ArrayBuffer|Uint8Array} stream the stream to read.
21722 */
21723 function StreamReader(stream) {
21724 this.stream = "";
21725 if (JSZip.support.uint8array && stream instanceof Uint8Array) {
21726 this.stream = JSZip.utils.uint8Array2String(stream);
21727 } else if (JSZip.support.arraybuffer && stream instanceof ArrayBuffer) {
21728 var bufferView = new Uint8Array(stream);
21729 this.stream = JSZip.utils.uint8Array2String(bufferView);
21730 } else {
21731 this.stream = JSZip.utils.string2binary(stream);
21732 }
21733 this.index = 0;
21734 }
21735 StreamReader.prototype = {
21736 /**
21737 * Check that the offset will not go too far.
21738 * @param {string} offset the additional offset to check.
21739 * @throws {Error} an Error if the offset is out of bounds.
21740 */
21741 checkOffset : function (offset) {
21742 this.checkIndex(this.index + offset);
21743 },
21744 /**
21745 * Check that the specifed index will not be too far.
21746 * @param {string} newIndex the index to check.
21747 * @throws {Error} an Error if the index is out of bounds.
21748 */
21749 checkIndex : function (newIndex) {
21750 if (this.stream.length < newIndex || newIndex < 0) {
21751 throw new Error("End of stream reached (stream length = " +
21752 this.stream.length + ", asked index = " +
21753 (newIndex) + "). Corrupted zip ?");
21754 }
21755 },
21756 /**
21757 * Change the index.
21758 * @param {number} newIndex The new index.
21759 * @throws {Error} if the new index is out of the stream.
21760 */
21761 setIndex : function (newIndex) {
21762 this.checkIndex(newIndex);
21763 this.index = newIndex;
21764 },
21765 /**
21766 * Skip the next n bytes.
21767 * @param {number} n the number of bytes to skip.
21768 * @throws {Error} if the new index is out of the stream.
21769 */
21770 skip : function (n) {
21771 this.setIndex(this.index + n);
21772 },
21773 /**
21774 * Get the byte at the specified index.
21775 * @param {number} i the index to use.
21776 * @return {number} a byte.
21777 */
21778 byteAt : function(i) {
21779 return this.stream.charCodeAt(i);
21780 },
21781 /**
21782 * Get the next number with a given byte size.
21783 * @param {number} size the number of bytes to read.
21784 * @return {number} the corresponding number.
21785 */
21786 readInt : function (size) {
21787 var result = 0, i;
21788 this.checkOffset(size);
21789 for(i = this.index + size - 1; i >= this.index; i--) {
21790 result = (result << 8) + this.byteAt(i);
21791 }
21792 this.index += size;
21793 return result;
21794 },
21795 /**
21796 * Get the next string with a given byte size.
21797 * @param {number} size the number of bytes to read.
21798 * @return {string} the corresponding string.
21799 */
21800 readString : function (size) {
21801 this.checkOffset(size);
21802 // this will work because the constructor applied the "& 0xff" mask.
21803 var result = this.stream.slice(this.index, this.index + size);
21804 this.index += size;
21805 return result;
21806 },
21807 /**
21808 * Get the next date.
21809 * @return {Date} the date.
21810 */
21811 readDate : function () {
21812 var dostime = this.readInt(4);
21813 return new Date(
21814 ((dostime >> 25) & 0x7f) + 1980, // year
21815 ((dostime >> 21) & 0x0f) - 1, // month
21816 (dostime >> 16) & 0x1f, // day
21817 (dostime >> 11) & 0x1f, // hour
21818 (dostime >> 5) & 0x3f, // minute
21819 (dostime & 0x1f) << 1); // second
21820 }
21821 };
21822 // }}} end of StreamReader
21823
21824 // class ZipEntry {{{
21825 /**
21826 * An entry in the zip file.
21827 * @constructor
21828 * @param {Object} options Options of the current file.
21829 * @param {Object} loadOptions Options for loading the stream.
21830 */
21831 function ZipEntry(options, loadOptions) {
21832 this.options = options;
21833 this.loadOptions = loadOptions;
21834 }
21835 ZipEntry.prototype = {
21836 /**
21837 * say if the file is encrypted.
21838 * @return {boolean} true if the file is encrypted, false otherwise.
21839 */
21840 isEncrypted : function () {
21841 // bit 1 is set
21842 return (this.bitFlag & 0x0001) === 0x0001;
21843 },
21844 /**
21845 * say if the file has utf-8 filename/comment.
21846 * @return {boolean} true if the filename/comment is in utf-8, false otherwise.
21847 */
21848 useUTF8 : function () {
21849 // bit 11 is set
21850 return (this.bitFlag & 0x0800) === 0x0800;
21851 },
21852 /**
21853 * Read the local part of a zip file and add the info in this object.
21854 * @param {StreamReader} reader the reader to use.
21855 */
21856 readLocalPart : function(reader) {
21857 var compression, localExtraFieldsLength;
21858
21859 // we already know everything from the central dir !
21860 // If the central dir data are false, we are doomed.
21861 // On the bright side, the local part is scary : zip64, data descriptors, both, etc.
21862 // The less data we get here, the more reliable this should be.
21863 // Let's skip the whole header and dash to the data !
21864 reader.skip(22);
21865 // in some zip created on windows, the filename stored in the central dir contains \ instead of /.
21866 // Strangely, the filename here is OK.
21867 // I would love to treat these zip files as corrupted (see http://www.info-zip.org/FAQ.html#backslashes
21868 // or APPNOTE#4.4.17.1, "All slashes MUST be forward slashes '/'") but there are a lot of bad zip generators...
21869 // Search "unzip mismatching "local" filename continuing with "central" filename version" on
21870 // the internet.
21871 //
21872 // I think I see the logic here : the central directory is used to display
21873 // content and the local directory is used to extract the files. Mixing / and \
21874 // may be used to display \ to windows users and use / when extracting the files.
21875 // Unfortunately, this lead also to some issues : http://seclists.org/fulldisclosure/2009/Sep/394
21876 this.fileNameLength = reader.readInt(2);
21877 localExtraFieldsLength = reader.readInt(2); // can't be sure this will be the same as the central dir
21878 this.fileName = reader.readString(this.fileNameLength);
21879 reader.skip(localExtraFieldsLength);
21880
21881 if (this.compressedSize == -1 || this.uncompressedSize == -1) {
21882 throw new Error("Bug or corrupted zip : didn't get enough informations from the central directory " +
21883 "(compressedSize == -1 || uncompressedSize == -1)");
21884 }
21885 this.compressedFileData = reader.readString(this.compressedSize);
21886
21887 compression = findCompression(this.compressionMethod);
21888 if (compression === null) { // no compression found
21889 throw new Error("Corrupted zip : compression " + pretty(this.compressionMethod) +
21890 " unknown (inner file : " + this.fileName + ")");
21891 }
21892 this.uncompressedFileData = compression.uncompress(this.compressedFileData);
21893
21894 if (this.uncompressedFileData.length !== this.uncompressedSize) {
21895 throw new Error("Bug : uncompressed data size mismatch");
21896 }
21897
21898 if (this.loadOptions.checkCRC32 && JSZip.prototype.crc32(this.uncompressedFileData) !== this.crc32) {
21899 throw new Error("Corrupted zip : CRC32 mismatch");
21900 }
21901 },
21902
21903 /**
21904 * Read the central part of a zip file and add the info in this object.
21905 * @param {StreamReader} reader the reader to use.
21906 */
21907 readCentralPart : function(reader) {
21908 this.versionMadeBy = reader.readString(2);
21909 this.versionNeeded = reader.readInt(2);
21910 this.bitFlag = reader.readInt(2);
21911 this.compressionMethod = reader.readString(2);
21912 this.date = reader.readDate();
21913 this.crc32 = reader.readInt(4);
21914 this.compressedSize = reader.readInt(4);
21915 this.uncompressedSize = reader.readInt(4);
21916 this.fileNameLength = reader.readInt(2);
21917 this.extraFieldsLength = reader.readInt(2);
21918 this.fileCommentLength = reader.readInt(2);
21919 this.diskNumberStart = reader.readInt(2);
21920 this.internalFileAttributes = reader.readInt(2);
21921 this.externalFileAttributes = reader.readInt(4);
21922 this.localHeaderOffset = reader.readInt(4);
21923
21924 if (this.isEncrypted()) {
21925 throw new Error("Encrypted zip are not supported");
21926 }
21927
21928 this.fileName = reader.readString(this.fileNameLength);
21929 this.readExtraFields(reader);
21930 this.parseZIP64ExtraField(reader);
21931 this.fileComment = reader.readString(this.fileCommentLength);
21932
21933 // warning, this is true only for zip with madeBy == DOS (plateform dependent feature)
21934 this.dir = this.externalFileAttributes & 0x00000010 ? true : false;
21935 },
21936 /**
21937 * Parse the ZIP64 extra field and merge the info in the current ZipEntry.
21938 * @param {StreamReader} reader the reader to use.
21939 */
21940 parseZIP64ExtraField : function(reader) {
21941
21942 if(!this.extraFields[0x0001]) {
21943 return;
21944 }
21945
21946 // should be something, preparing the extra reader
21947 var extraReader = new StreamReader(this.extraFields[0x0001].value);
21948
21949 // I really hope that these 64bits integer can fit in 32 bits integer, because js
21950 // won't let us have more.
21951 if(this.uncompressedSize === MAX_VALUE_32BITS) {
21952 this.uncompressedSize = extraReader.readInt(8);
21953 }
21954 if(this.compressedSize === MAX_VALUE_32BITS) {
21955 this.compressedSize = extraReader.readInt(8);
21956 }
21957 if(this.localHeaderOffset === MAX_VALUE_32BITS) {
21958 this.localHeaderOffset = extraReader.readInt(8);
21959 }
21960 if(this.diskNumberStart === MAX_VALUE_32BITS) {
21961 this.diskNumberStart = extraReader.readInt(4);
21962 }
21963 },
21964 /**
21965 * Read the central part of a zip file and add the info in this object.
21966 * @param {StreamReader} reader the reader to use.
21967 */
21968 readExtraFields : function(reader) {
21969 var start = reader.index,
21970 extraFieldId,
21971 extraFieldLength,
21972 extraFieldValue;
21973
21974 this.extraFields = this.extraFields || {};
21975
21976 while (reader.index < start + this.extraFieldsLength) {
21977 extraFieldId = reader.readInt(2);
21978 extraFieldLength = reader.readInt(2);
21979 extraFieldValue = reader.readString(extraFieldLength);
21980
21981 this.extraFields[extraFieldId] = {
21982 id: extraFieldId,
21983 length: extraFieldLength,
21984 value: extraFieldValue
21985 };
21986 }
21987 },
21988 /**
21989 * Apply an UTF8 transformation if needed.
21990 */
21991 handleUTF8 : function() {
21992 if (this.useUTF8()) {
21993 this.fileName = JSZip.prototype.utf8decode(this.fileName);
21994 this.fileComment = JSZip.prototype.utf8decode(this.fileComment);
21995 }
21996 }
21997 };
21998 // }}} end of ZipEntry
21999
22000 // class ZipEntries {{{
22001 /**
22002 * All the entries in the zip file.
22003 * @constructor
22004 * @param {String|ArrayBuffer|Uint8Array} data the binary stream to load.
22005 * @param {Object} loadOptions Options for loading the stream.
22006 */
22007 function ZipEntries(data, loadOptions) {
22008 this.files = [];
22009 this.loadOptions = loadOptions;
22010 if (data) {
22011 this.load(data);
22012 }
22013 }
22014 ZipEntries.prototype = {
22015 /**
22016 * Check that the reader is on the speficied signature.
22017 * @param {string} expectedSignature the expected signature.
22018 * @throws {Error} if it is an other signature.
22019 */
22020 checkSignature : function(expectedSignature) {
22021 var signature = this.reader.readString(4);
22022 if (signature !== expectedSignature) {
22023 throw new Error("Corrupted zip or bug : unexpected signature " +
22024 "(" + pretty(signature) + ", expected " + pretty(expectedSignature) + ")");
22025 }
22026 },
22027 /**
22028 * Read the end of the central directory.
22029 */
22030 readBlockEndOfCentral : function () {
22031 this.diskNumber = this.reader.readInt(2);
22032 this.diskWithCentralDirStart = this.reader.readInt(2);
22033 this.centralDirRecordsOnThisDisk = this.reader.readInt(2);
22034 this.centralDirRecords = this.reader.readInt(2);
22035 this.centralDirSize = this.reader.readInt(4);
22036 this.centralDirOffset = this.reader.readInt(4);
22037
22038 this.zipCommentLength = this.reader.readInt(2);
22039 this.zipComment = this.reader.readString(this.zipCommentLength);
22040 },
22041 /**
22042 * Read the end of the Zip 64 central directory.
22043 * Not merged with the method readEndOfCentral :
22044 * The end of central can coexist with its Zip64 brother,
22045 * I don't want to read the wrong number of bytes !
22046 */
22047 readBlockZip64EndOfCentral : function () {
22048 this.zip64EndOfCentralSize = this.reader.readInt(8);
22049 this.versionMadeBy = this.reader.readString(2);
22050 this.versionNeeded = this.reader.readInt(2);
22051 this.diskNumber = this.reader.readInt(4);
22052 this.diskWithCentralDirStart = this.reader.readInt(4);
22053 this.centralDirRecordsOnThisDisk = this.reader.readInt(8);
22054 this.centralDirRecords = this.reader.readInt(8);
22055 this.centralDirSize = this.reader.readInt(8);
22056 this.centralDirOffset = this.reader.readInt(8);
22057
22058 this.zip64ExtensibleData = {};
22059 var extraDataSize = this.zip64EndOfCentralSize - 44,
22060 index = 0,
22061 extraFieldId,
22062 extraFieldLength,
22063 extraFieldValue;
22064 while(index < extraDataSize) {
22065 extraFieldId = this.reader.readInt(2);
22066 extraFieldLength = this.reader.readInt(4);
22067 extraFieldValue = this.reader.readString(extraFieldLength);
22068 this.zip64ExtensibleData[extraFieldId] = {
22069 id: extraFieldId,
22070 length: extraFieldLength,
22071 value: extraFieldValue
22072 };
22073 }
22074 },
22075 /**
22076 * Read the end of the Zip 64 central directory locator.
22077 */
22078 readBlockZip64EndOfCentralLocator : function () {
22079 this.diskWithZip64CentralDirStart = this.reader.readInt(4);
22080 this.relativeOffsetEndOfZip64CentralDir = this.reader.readInt(8);
22081 this.disksCount = this.reader.readInt(4);
22082 if (this.disksCount > 1) {
22083 throw new Error("Multi-volumes zip are not supported");
22084 }
22085 },
22086 /**
22087 * Read the local files, based on the offset read in the central part.
22088 */
22089 readLocalFiles : function() {
22090 var i, file;
22091 for(i = 0; i < this.files.length; i++) {
22092 file = this.files[i];
22093 this.reader.setIndex(file.localHeaderOffset);
22094 this.checkSignature(JSZip.signature.LOCAL_FILE_HEADER);
22095 file.readLocalPart(this.reader);
22096 file.handleUTF8();
22097 }
22098 },
22099 /**
22100 * Read the central directory.
22101 */
22102 readCentralDir : function() {
22103 var file;
22104
22105 this.reader.setIndex(this.centralDirOffset);
22106 while(this.reader.readString(4) === JSZip.signature.CENTRAL_FILE_HEADER) {
22107 file = new ZipEntry({
22108 zip64: this.zip64
22109 }, this.loadOptions);
22110 file.readCentralPart(this.reader);
22111 this.files.push(file);
22112 }
22113 },
22114 /**
22115 * Read the end of central directory.
22116 */
22117 readEndOfCentral : function() {
22118 var offset = this.reader.stream.lastIndexOf(JSZip.signature.CENTRAL_DIRECTORY_END);
22119 if (offset === -1) {
22120 throw new Error("Corrupted zip : can't find end of central directory");
22121 }
22122 this.reader.setIndex(offset);
22123 this.checkSignature(JSZip.signature.CENTRAL_DIRECTORY_END);
22124 this.readBlockEndOfCentral();
22125
22126
22127 /* extract from the zip spec :
22128 4) If one of the fields in the end of central directory
22129 record is too small to hold required data, the field
22130 should be set to -1 (0xFFFF or 0xFFFFFFFF) and the
22131 ZIP64 format record should be created.
22132 5) The end of central directory record and the
22133 Zip64 end of central directory locator record must
22134 reside on the same disk when splitting or spanning
22135 an archive.
22136 */
22137 if ( this.diskNumber === MAX_VALUE_16BITS
22138 || this.diskWithCentralDirStart === MAX_VALUE_16BITS
22139 || this.centralDirRecordsOnThisDisk === MAX_VALUE_16BITS
22140 || this.centralDirRecords === MAX_VALUE_16BITS
22141 || this.centralDirSize === MAX_VALUE_32BITS
22142 || this.centralDirOffset === MAX_VALUE_32BITS
22143 ) {
22144 this.zip64 = true;
22145
22146 /*
22147 Warning : the zip64 extension is supported, but ONLY if the 64bits integer read from
22148 the zip file can fit into a 32bits integer. This cannot be solved : Javascript represents
22149 all numbers as 64-bit double precision IEEE 754 floating point numbers.
22150 So, we have 53bits for integers and bitwise operations treat everything as 32bits.
22151 see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Bitwise_Operators
22152 and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf section 8.5
22153 */
22154
22155 // should look for a zip64 EOCD locator
22156 offset = this.reader.stream.lastIndexOf(JSZip.signature.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
22157 if (offset === -1) {
22158 throw new Error("Corrupted zip : can't find the ZIP64 end of central directory locator");
22159 }
22160 this.reader.setIndex(offset);
22161 this.checkSignature(JSZip.signature.ZIP64_CENTRAL_DIRECTORY_LOCATOR);
22162 this.readBlockZip64EndOfCentralLocator();
22163
22164 // now the zip64 EOCD record
22165 this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);
22166 this.checkSignature(JSZip.signature.ZIP64_CENTRAL_DIRECTORY_END);
22167 this.readBlockZip64EndOfCentral();
22168 }
22169 },
22170 /**
22171 * Read a zip file and create ZipEntries.
22172 * @param {String|ArrayBuffer|Uint8Array} data the binary string representing a zip file.
22173 */
22174 load : function(data) {
22175 this.reader = new StreamReader(data);
22176
22177 this.readEndOfCentral();
22178 this.readCentralDir();
22179 this.readLocalFiles();
22180 }
22181 };
22182 // }}} end of ZipEntries
22183
22184 /**
22185 * Implementation of the load method of JSZip.
22186 * It uses the above classes to decode a zip file, and load every files.
22187 * @param {String|ArrayBuffer|Uint8Array} data the data to load.
22188 * @param {Object} options Options for loading the stream.
22189 * options.base64 : is the stream in base64 ? default : false
22190 */
22191 JSZip.prototype.load = function(data, options) {
22192 var files, zipEntries, i, input;
22193 options = options || {};
22194 if(options.base64) {
22195 data = JSZipBase64.decode(data);
22196 }
22197
22198 zipEntries = new ZipEntries(data, options);
22199 files = zipEntries.files;
22200 for (i = 0; i < files.length; i++) {
22201 input = files[i];
22202 this.file(input.fileName, input.uncompressedFileData, {
22203 binary:true,
22204 optimizedBinaryString:true,
22205 date:input.date,
22206 dir:input.dir
22207 });
22208 }
22209
22210 return this;
22211 };
22212
22213 }());
22214 // enforcing Stuk's coding style
22215 // vim: set shiftwidth=3 softtabstop=3 foldmethod=marker:
22216 //! moment.js
22217 //! version : 2.5.1
22218 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
22219 //! license : MIT
22220 //! momentjs.com
22221
22222 (function (undefined) {
22223
22224 /************************************
22225 Constants
22226 ************************************/
22227
22228 var moment,
22229 VERSION = "2.5.1",
22230 global = this,
22231 round = Math.round,
22232 i,
22233
22234 YEAR = 0,
22235 MONTH = 1,
22236 DATE = 2,
22237 HOUR = 3,
22238 MINUTE = 4,
22239 SECOND = 5,
22240 MILLISECOND = 6,
22241
22242 // internal storage for language config files
22243 languages = {},
22244
22245 // moment internal properties
22246 momentProperties = {
22247 _isAMomentObject: null,
22248 _i : null,
22249 _f : null,
22250 _l : null,
22251 _strict : null,
22252 _isUTC : null,
22253 _offset : null, // optional. Combine with _isUTC
22254 _pf : null,
22255 _lang : null // optional
22256 },
22257
22258 // check for nodeJS
22259 hasModule = (typeof module !== 'undefined' && module.exports && typeof require !== 'undefined'),
22260
22261 // ASP.NET json date format regex
22262 aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
22263 aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/,
22264
22265 // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html
22266 // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere
22267 isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
22268
22269 // format tokens
22270 formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
22271 localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
22272
22273 // parsing token regexes
22274 parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
22275 parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999
22276 parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999
22277 parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999
22278 parseTokenDigits = /\d+/, // nonzero number of digits
22279 parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
22280 parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
22281 parseTokenT = /T/i, // T (ISO separator)
22282 parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
22283
22284 //strict parsing regexes
22285 parseTokenOneDigit = /\d/, // 0 - 9
22286 parseTokenTwoDigits = /\d\d/, // 00 - 99
22287 parseTokenThreeDigits = /\d{3}/, // 000 - 999
22288 parseTokenFourDigits = /\d{4}/, // 0000 - 9999
22289 parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999
22290 parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf
22291
22292 // iso 8601 regex
22293 // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
22294 isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
22295
22296 isoFormat = 'YYYY-MM-DDTHH:mm:ssZ',
22297
22298 isoDates = [
22299 ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/],
22300 ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/],
22301 ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/],
22302 ['GGGG-[W]WW', /\d{4}-W\d{2}/],
22303 ['YYYY-DDD', /\d{4}-\d{3}/]
22304 ],
22305
22306 // iso time formats and regexes
22307 isoTimes = [
22308 ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d{1,3}/],
22309 ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/],
22310 ['HH:mm', /(T| )\d\d:\d\d/],
22311 ['HH', /(T| )\d\d/]
22312 ],
22313
22314 // timezone chunker "+10:00" > ["10", "00"] or "-1530" > ["-15", "30"]
22315 parseTimezoneChunker = /([\+\-]|\d\d)/gi,
22316
22317 // getter and setter names
22318 proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'),
22319 unitMillisecondFactors = {
22320 'Milliseconds' : 1,
22321 'Seconds' : 1e3,
22322 'Minutes' : 6e4,
22323 'Hours' : 36e5,
22324 'Days' : 864e5,
22325 'Months' : 2592e6,
22326 'Years' : 31536e6
22327 },
22328
22329 unitAliases = {
22330 ms : 'millisecond',
22331 s : 'second',
22332 m : 'minute',
22333 h : 'hour',
22334 d : 'day',
22335 D : 'date',
22336 w : 'week',
22337 W : 'isoWeek',
22338 M : 'month',
22339 y : 'year',
22340 DDD : 'dayOfYear',
22341 e : 'weekday',
22342 E : 'isoWeekday',
22343 gg: 'weekYear',
22344 GG: 'isoWeekYear'
22345 },
22346
22347 camelFunctions = {
22348 dayofyear : 'dayOfYear',
22349 isoweekday : 'isoWeekday',
22350 isoweek : 'isoWeek',
22351 weekyear : 'weekYear',
22352 isoweekyear : 'isoWeekYear'
22353 },
22354
22355 // format function strings
22356 formatFunctions = {},
22357
22358 // tokens to ordinalize and pad
22359 ordinalizeTokens = 'DDD w W M D d'.split(' '),
22360 paddedTokens = 'M D H h m s w W'.split(' '),
22361
22362 formatTokenFunctions = {
22363 M : function () {
22364 return this.month() + 1;
22365 },
22366 MMM : function (format) {
22367 return this.lang().monthsShort(this, format);
22368 },
22369 MMMM : function (format) {
22370 return this.lang().months(this, format);
22371 },
22372 D : function () {
22373 return this.date();
22374 },
22375 DDD : function () {
22376 return this.dayOfYear();
22377 },
22378 d : function () {
22379 return this.day();
22380 },
22381 dd : function (format) {
22382 return this.lang().weekdaysMin(this, format);
22383 },
22384 ddd : function (format) {
22385 return this.lang().weekdaysShort(this, format);
22386 },
22387 dddd : function (format) {
22388 return this.lang().weekdays(this, format);
22389 },
22390 w : function () {
22391 return this.week();
22392 },
22393 W : function () {
22394 return this.isoWeek();
22395 },
22396 YY : function () {
22397 return leftZeroFill(this.year() % 100, 2);
22398 },
22399 YYYY : function () {
22400 return leftZeroFill(this.year(), 4);
22401 },
22402 YYYYY : function () {
22403 return leftZeroFill(this.year(), 5);
22404 },
22405 YYYYYY : function () {
22406 var y = this.year(), sign = y >= 0 ? '+' : '-';
22407 return sign + leftZeroFill(Math.abs(y), 6);
22408 },
22409 gg : function () {
22410 return leftZeroFill(this.weekYear() % 100, 2);
22411 },
22412 gggg : function () {
22413 return leftZeroFill(this.weekYear(), 4);
22414 },
22415 ggggg : function () {
22416 return leftZeroFill(this.weekYear(), 5);
22417 },
22418 GG : function () {
22419 return leftZeroFill(this.isoWeekYear() % 100, 2);
22420 },
22421 GGGG : function () {
22422 return leftZeroFill(this.isoWeekYear(), 4);
22423 },
22424 GGGGG : function () {
22425 return leftZeroFill(this.isoWeekYear(), 5);
22426 },
22427 e : function () {
22428 return this.weekday();
22429 },
22430 E : function () {
22431 return this.isoWeekday();
22432 },
22433 a : function () {
22434 return this.lang().meridiem(this.hours(), this.minutes(), true);
22435 },
22436 A : function () {
22437 return this.lang().meridiem(this.hours(), this.minutes(), false);
22438 },
22439 H : function () {
22440 return this.hours();
22441 },
22442 h : function () {
22443 return this.hours() % 12 || 12;
22444 },
22445 m : function () {
22446 return this.minutes();
22447 },
22448 s : function () {
22449 return this.seconds();
22450 },
22451 S : function () {
22452 return toInt(this.milliseconds() / 100);
22453 },
22454 SS : function () {
22455 return leftZeroFill(toInt(this.milliseconds() / 10), 2);
22456 },
22457 SSS : function () {
22458 return leftZeroFill(this.milliseconds(), 3);
22459 },
22460 SSSS : function () {
22461 return leftZeroFill(this.milliseconds(), 3);
22462 },
22463 Z : function () {
22464 var a = -this.zone(),
22465 b = "+";
22466 if (a < 0) {
22467 a = -a;
22468 b = "-";
22469 }
22470 return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2);
22471 },
22472 ZZ : function () {
22473 var a = -this.zone(),
22474 b = "+";
22475 if (a < 0) {
22476 a = -a;
22477 b = "-";
22478 }
22479 return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2);
22480 },
22481 z : function () {
22482 return this.zoneAbbr();
22483 },
22484 zz : function () {
22485 return this.zoneName();
22486 },
22487 X : function () {
22488 return this.unix();
22489 },
22490 Q : function () {
22491 return this.quarter();
22492 }
22493 },
22494
22495 lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin'];
22496
22497 function defaultParsingFlags() {
22498 // We need to deep clone this object, and es5 standard is not very
22499 // helpful.
22500 return {
22501 empty : false,
22502 unusedTokens : [],
22503 unusedInput : [],
22504 overflow : -2,
22505 charsLeftOver : 0,
22506 nullInput : false,
22507 invalidMonth : null,
22508 invalidFormat : false,
22509 userInvalidated : false,
22510 iso: false
22511 };
22512 }
22513
22514 function padToken(func, count) {
22515 return function (a) {
22516 return leftZeroFill(func.call(this, a), count);
22517 };
22518 }
22519 function ordinalizeToken(func, period) {
22520 return function (a) {
22521 return this.lang().ordinal(func.call(this, a), period);
22522 };
22523 }
22524
22525 while (ordinalizeTokens.length) {
22526 i = ordinalizeTokens.pop();
22527 formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i);
22528 }
22529 while (paddedTokens.length) {
22530 i = paddedTokens.pop();
22531 formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2);
22532 }
22533 formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3);
22534
22535
22536 /************************************
22537 Constructors
22538 ************************************/
22539
22540 function Language() {
22541
22542 }
22543
22544 // Moment prototype object
22545 function Moment(config) {
22546 checkOverflow(config);
22547 extend(this, config);
22548 }
22549
22550 // Duration Constructor
22551 function Duration(duration) {
22552 var normalizedInput = normalizeObjectUnits(duration),
22553 years = normalizedInput.year || 0,
22554 months = normalizedInput.month || 0,
22555 weeks = normalizedInput.week || 0,
22556 days = normalizedInput.day || 0,
22557 hours = normalizedInput.hour || 0,
22558 minutes = normalizedInput.minute || 0,
22559 seconds = normalizedInput.second || 0,
22560 milliseconds = normalizedInput.millisecond || 0;
22561
22562 // representation for dateAddRemove
22563 this._milliseconds = +milliseconds +
22564 seconds * 1e3 + // 1000
22565 minutes * 6e4 + // 1000 * 60
22566 hours * 36e5; // 1000 * 60 * 60
22567 // Because of dateAddRemove treats 24 hours as different from a
22568 // day when working around DST, we need to store them separately
22569 this._days = +days +
22570 weeks * 7;
22571 // It is impossible translate months into days without knowing
22572 // which months you are are talking about, so we have to store
22573 // it separately.
22574 this._months = +months +
22575 years * 12;
22576
22577 this._data = {};
22578
22579 this._bubble();
22580 }
22581
22582 /************************************
22583 Helpers
22584 ************************************/
22585
22586
22587 function extend(a, b) {
22588 for (var i in b) {
22589 if (b.hasOwnProperty(i)) {
22590 a[i] = b[i];
22591 }
22592 }
22593
22594 if (b.hasOwnProperty("toString")) {
22595 a.toString = b.toString;
22596 }
22597
22598 if (b.hasOwnProperty("valueOf")) {
22599 a.valueOf = b.valueOf;
22600 }
22601
22602 return a;
22603 }
22604
22605 function cloneMoment(m) {
22606 var result = {}, i;
22607 for (i in m) {
22608 if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) {
22609 result[i] = m[i];
22610 }
22611 }
22612
22613 return result;
22614 }
22615
22616 function absRound(number) {
22617 if (number < 0) {
22618 return Math.ceil(number);
22619 } else {
22620 return Math.floor(number);
22621 }
22622 }
22623
22624 // left zero fill a number
22625 // see http://jsperf.com/left-zero-filling for performance comparison
22626 function leftZeroFill(number, targetLength, forceSign) {
22627 var output = '' + Math.abs(number),
22628 sign = number >= 0;
22629
22630 while (output.length < targetLength) {
22631 output = '0' + output;
22632 }
22633 return (sign ? (forceSign ? '+' : '') : '-') + output;
22634 }
22635
22636 // helper function for _.addTime and _.subtractTime
22637 function addOrSubtractDurationFromMoment(mom, duration, isAdding, ignoreUpdateOffset) {
22638 var milliseconds = duration._milliseconds,
22639 days = duration._days,
22640 months = duration._months,
22641 minutes,
22642 hours;
22643
22644 if (milliseconds) {
22645 mom._d.setTime(+mom._d + milliseconds * isAdding);
22646 }
22647 // store the minutes and hours so we can restore them
22648 if (days || months) {
22649 minutes = mom.minute();
22650 hours = mom.hour();
22651 }
22652 if (days) {
22653 mom.date(mom.date() + days * isAdding);
22654 }
22655 if (months) {
22656 mom.month(mom.month() + months * isAdding);
22657 }
22658 if (milliseconds && !ignoreUpdateOffset) {
22659 moment.updateOffset(mom);
22660 }
22661 // restore the minutes and hours after possibly changing dst
22662 if (days || months) {
22663 mom.minute(minutes);
22664 mom.hour(hours);
22665 }
22666 }
22667
22668 // check if is an array
22669 function isArray(input) {
22670 return Object.prototype.toString.call(input) === '[object Array]';
22671 }
22672
22673 function isDate(input) {
22674 return Object.prototype.toString.call(input) === '[object Date]' ||
22675 input instanceof Date;
22676 }
22677
22678 // compare two arrays, return the number of differences
22679 function compareArrays(array1, array2, dontConvert) {
22680 var len = Math.min(array1.length, array2.length),
22681 lengthDiff = Math.abs(array1.length - array2.length),
22682 diffs = 0,
22683 i;
22684 for (i = 0; i < len; i++) {
22685 if ((dontConvert && array1[i] !== array2[i]) ||
22686 (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {
22687 diffs++;
22688 }
22689 }
22690 return diffs + lengthDiff;
22691 }
22692
22693 function normalizeUnits(units) {
22694 if (units) {
22695 var lowered = units.toLowerCase().replace(/(.)s$/, '$1');
22696 units = unitAliases[units] || camelFunctions[lowered] || lowered;
22697 }
22698 return units;
22699 }
22700
22701 function normalizeObjectUnits(inputObject) {
22702 var normalizedInput = {},
22703 normalizedProp,
22704 prop;
22705
22706 for (prop in inputObject) {
22707 if (inputObject.hasOwnProperty(prop)) {
22708 normalizedProp = normalizeUnits(prop);
22709 if (normalizedProp) {
22710 normalizedInput[normalizedProp] = inputObject[prop];
22711 }
22712 }
22713 }
22714
22715 return normalizedInput;
22716 }
22717
22718 function makeList(field) {
22719 var count, setter;
22720
22721 if (field.indexOf('week') === 0) {
22722 count = 7;
22723 setter = 'day';
22724 }
22725 else if (field.indexOf('month') === 0) {
22726 count = 12;
22727 setter = 'month';
22728 }
22729 else {
22730 return;
22731 }
22732
22733 moment[field] = function (format, index) {
22734 var i, getter,
22735 method = moment.fn._lang[field],
22736 results = [];
22737
22738 if (typeof format === 'number') {
22739 index = format;
22740 format = undefined;
22741 }
22742
22743 getter = function (i) {
22744 var m = moment().utc().set(setter, i);
22745 return method.call(moment.fn._lang, m, format || '');
22746 };
22747
22748 if (index != null) {
22749 return getter(index);
22750 }
22751 else {
22752 for (i = 0; i < count; i++) {
22753 results.push(getter(i));
22754 }
22755 return results;
22756 }
22757 };
22758 }
22759
22760 function toInt(argumentForCoercion) {
22761 var coercedNumber = +argumentForCoercion,
22762 value = 0;
22763
22764 if (coercedNumber !== 0 && isFinite(coercedNumber)) {
22765 if (coercedNumber >= 0) {
22766 value = Math.floor(coercedNumber);
22767 } else {
22768 value = Math.ceil(coercedNumber);
22769 }
22770 }
22771
22772 return value;
22773 }
22774
22775 function daysInMonth(year, month) {
22776 return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();
22777 }
22778
22779 function daysInYear(year) {
22780 return isLeapYear(year) ? 366 : 365;
22781 }
22782
22783 function isLeapYear(year) {
22784 return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
22785 }
22786
22787 function checkOverflow(m) {
22788 var overflow;
22789 if (m._a && m._pf.overflow === -2) {
22790 overflow =
22791 m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
22792 m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
22793 m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
22794 m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
22795 m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
22796 m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
22797 -1;
22798
22799 if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {
22800 overflow = DATE;
22801 }
22802
22803 m._pf.overflow = overflow;
22804 }
22805 }
22806
22807 function isValid(m) {
22808 if (m._isValid == null) {
22809 m._isValid = !isNaN(m._d.getTime()) &&
22810 m._pf.overflow < 0 &&
22811 !m._pf.empty &&
22812 !m._pf.invalidMonth &&
22813 !m._pf.nullInput &&
22814 !m._pf.invalidFormat &&
22815 !m._pf.userInvalidated;
22816
22817 if (m._strict) {
22818 m._isValid = m._isValid &&
22819 m._pf.charsLeftOver === 0 &&
22820 m._pf.unusedTokens.length === 0;
22821 }
22822 }
22823 return m._isValid;
22824 }
22825
22826 function normalizeLanguage(key) {
22827 return key ? key.toLowerCase().replace('_', '-') : key;
22828 }
22829
22830 // Return a moment from input, that is local/utc/zone equivalent to model.
22831 function makeAs(input, model) {
22832 return model._isUTC ? moment(input).zone(model._offset || 0) :
22833 moment(input).local();
22834 }
22835
22836 /************************************
22837 Languages
22838 ************************************/
22839
22840
22841 extend(Language.prototype, {
22842
22843 set : function (config) {
22844 var prop, i;
22845 for (i in config) {
22846 prop = config[i];
22847 if (typeof prop === 'function') {
22848 this[i] = prop;
22849 } else {
22850 this['_' + i] = prop;
22851 }
22852 }
22853 },
22854
22855 _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
22856 months : function (m) {
22857 return this._months[m.month()];
22858 },
22859
22860 _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),
22861 monthsShort : function (m) {
22862 return this._monthsShort[m.month()];
22863 },
22864
22865 monthsParse : function (monthName) {
22866 var i, mom, regex;
22867
22868 if (!this._monthsParse) {
22869 this._monthsParse = [];
22870 }
22871
22872 for (i = 0; i < 12; i++) {
22873 // make the regex if we don't have it already
22874 if (!this._monthsParse[i]) {
22875 mom = moment.utc([2000, i]);
22876 regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
22877 this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
22878 }
22879 // test the regex
22880 if (this._monthsParse[i].test(monthName)) {
22881 return i;
22882 }
22883 }
22884 },
22885
22886 _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
22887 weekdays : function (m) {
22888 return this._weekdays[m.day()];
22889 },
22890
22891 _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),
22892 weekdaysShort : function (m) {
22893 return this._weekdaysShort[m.day()];
22894 },
22895
22896 _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"),
22897 weekdaysMin : function (m) {
22898 return this._weekdaysMin[m.day()];
22899 },
22900
22901 weekdaysParse : function (weekdayName) {
22902 var i, mom, regex;
22903
22904 if (!this._weekdaysParse) {
22905 this._weekdaysParse = [];
22906 }
22907
22908 for (i = 0; i < 7; i++) {
22909 // make the regex if we don't have it already
22910 if (!this._weekdaysParse[i]) {
22911 mom = moment([2000, 1]).day(i);
22912 regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');
22913 this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');
22914 }
22915 // test the regex
22916 if (this._weekdaysParse[i].test(weekdayName)) {
22917 return i;
22918 }
22919 }
22920 },
22921
22922 _longDateFormat : {
22923 LT : "h:mm A",
22924 L : "MM/DD/YYYY",
22925 LL : "MMMM D YYYY",
22926 LLL : "MMMM D YYYY LT",
22927 LLLL : "dddd, MMMM D YYYY LT"
22928 },
22929 longDateFormat : function (key) {
22930 var output = this._longDateFormat[key];
22931 if (!output && this._longDateFormat[key.toUpperCase()]) {
22932 output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) {
22933 return val.slice(1);
22934 });
22935 this._longDateFormat[key] = output;
22936 }
22937 return output;
22938 },
22939
22940 isPM : function (input) {
22941 // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays
22942 // Using charAt should be more compatible.
22943 return ((input + '').toLowerCase().charAt(0) === 'p');
22944 },
22945
22946 _meridiemParse : /[ap]\.?m?\.?/i,
22947 meridiem : function (hours, minutes, isLower) {
22948 if (hours > 11) {
22949 return isLower ? 'pm' : 'PM';
22950 } else {
22951 return isLower ? 'am' : 'AM';
22952 }
22953 },
22954
22955 _calendar : {
22956 sameDay : '[Today at] LT',
22957 nextDay : '[Tomorrow at] LT',
22958 nextWeek : 'dddd [at] LT',
22959 lastDay : '[Yesterday at] LT',
22960 lastWeek : '[Last] dddd [at] LT',
22961 sameElse : 'L'
22962 },
22963 calendar : function (key, mom) {
22964 var output = this._calendar[key];
22965 return typeof output === 'function' ? output.apply(mom) : output;
22966 },
22967
22968 _relativeTime : {
22969 future : "in %s",
22970 past : "%s ago",
22971 s : "a few seconds",
22972 m : "a minute",
22973 mm : "%d minutes",
22974 h : "an hour",
22975 hh : "%d hours",
22976 d : "a day",
22977 dd : "%d days",
22978 M : "a month",
22979 MM : "%d months",
22980 y : "a year",
22981 yy : "%d years"
22982 },
22983 relativeTime : function (number, withoutSuffix, string, isFuture) {
22984 var output = this._relativeTime[string];
22985 return (typeof output === 'function') ?
22986 output(number, withoutSuffix, string, isFuture) :
22987 output.replace(/%d/i, number);
22988 },
22989 pastFuture : function (diff, output) {
22990 var format = this._relativeTime[diff > 0 ? 'future' : 'past'];
22991 return typeof format === 'function' ? format(output) : format.replace(/%s/i, output);
22992 },
22993
22994 ordinal : function (number) {
22995 return this._ordinal.replace("%d", number);
22996 },
22997 _ordinal : "%d",
22998
22999 preparse : function (string) {
23000 return string;
23001 },
23002
23003 postformat : function (string) {
23004 return string;
23005 },
23006
23007 week : function (mom) {
23008 return weekOfYear(mom, this._week.dow, this._week.doy).week;
23009 },
23010
23011 _week : {
23012 dow : 0, // Sunday is the first day of the week.
23013 doy : 6 // The week that contains Jan 1st is the first week of the year.
23014 },
23015
23016 _invalidDate: 'Invalid date',
23017 invalidDate: function () {
23018 return this._invalidDate;
23019 }
23020 });
23021
23022 // Loads a language definition into the `languages` cache. The function
23023 // takes a key and optionally values. If not in the browser and no values
23024 // are provided, it will load the language file module. As a convenience,
23025 // this function also returns the language values.
23026 function loadLang(key, values) {
23027 values.abbr = key;
23028 if (!languages[key]) {
23029 languages[key] = new Language();
23030 }
23031 languages[key].set(values);
23032 return languages[key];
23033 }
23034
23035 // Remove a language from the `languages` cache. Mostly useful in tests.
23036 function unloadLang(key) {
23037 delete languages[key];
23038 }
23039
23040 // Determines which language definition to use and returns it.
23041 //
23042 // With no parameters, it will return the global language. If you
23043 // pass in a language key, such as 'en', it will return the
23044 // definition for 'en', so long as 'en' has already been loaded using
23045 // moment.lang.
23046 function getLangDefinition(key) {
23047 var i = 0, j, lang, next, split,
23048 get = function (k) {
23049 if (!languages[k] && hasModule) {
23050 try {
23051 require('./lang/' + k);
23052 } catch (e) { }
23053 }
23054 return languages[k];
23055 };
23056
23057 if (!key) {
23058 return moment.fn._lang;
23059 }
23060
23061 if (!isArray(key)) {
23062 //short-circuit everything else
23063 lang = get(key);
23064 if (lang) {
23065 return lang;
23066 }
23067 key = [key];
23068 }
23069
23070 //pick the language from the array
23071 //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
23072 //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
23073 while (i < key.length) {
23074 split = normalizeLanguage(key[i]).split('-');
23075 j = split.length;
23076 next = normalizeLanguage(key[i + 1]);
23077 next = next ? next.split('-') : null;
23078 while (j > 0) {
23079 lang = get(split.slice(0, j).join('-'));
23080 if (lang) {
23081 return lang;
23082 }
23083 if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {
23084 //the next array item is better than a shallower substring of this one
23085 break;
23086 }
23087 j--;
23088 }
23089 i++;
23090 }
23091 return moment.fn._lang;
23092 }
23093
23094 /************************************
23095 Formatting
23096 ************************************/
23097
23098
23099 function removeFormattingTokens(input) {
23100 if (input.match(/\[[\s\S]/)) {
23101 return input.replace(/^\[|\]$/g, "");
23102 }
23103 return input.replace(/\\/g, "");
23104 }
23105
23106 function makeFormatFunction(format) {
23107 var array = format.match(formattingTokens), i, length;
23108
23109 for (i = 0, length = array.length; i < length; i++) {
23110 if (formatTokenFunctions[array[i]]) {
23111 array[i] = formatTokenFunctions[array[i]];
23112 } else {
23113 array[i] = removeFormattingTokens(array[i]);
23114 }
23115 }
23116
23117 return function (mom) {
23118 var output = "";
23119 for (i = 0; i < length; i++) {
23120 output += array[i] instanceof Function ? array[i].call(mom, format) : array[i];
23121 }
23122 return output;
23123 };
23124 }
23125
23126 // format date using native date object
23127 function formatMoment(m, format) {
23128
23129 if (!m.isValid()) {
23130 return m.lang().invalidDate();
23131 }
23132
23133 format = expandFormat(format, m.lang());
23134
23135 if (!formatFunctions[format]) {
23136 formatFunctions[format] = makeFormatFunction(format);
23137 }
23138
23139 return formatFunctions[format](m);
23140 }
23141
23142 function expandFormat(format, lang) {
23143 var i = 5;
23144
23145 function replaceLongDateFormatTokens(input) {
23146 return lang.longDateFormat(input) || input;
23147 }
23148
23149 localFormattingTokens.lastIndex = 0;
23150 while (i >= 0 && localFormattingTokens.test(format)) {
23151 format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);
23152 localFormattingTokens.lastIndex = 0;
23153 i -= 1;
23154 }
23155
23156 return format;
23157 }
23158
23159
23160 /************************************
23161 Parsing
23162 ************************************/
23163
23164
23165 // get the regex to find the next token
23166 function getParseRegexForToken(token, config) {
23167 var a, strict = config._strict;
23168 switch (token) {
23169 case 'DDDD':
23170 return parseTokenThreeDigits;
23171 case 'YYYY':
23172 case 'GGGG':
23173 case 'gggg':
23174 return strict ? parseTokenFourDigits : parseTokenOneToFourDigits;
23175 case 'Y':
23176 case 'G':
23177 case 'g':
23178 return parseTokenSignedNumber;
23179 case 'YYYYYY':
23180 case 'YYYYY':
23181 case 'GGGGG':
23182 case 'ggggg':
23183 return strict ? parseTokenSixDigits : parseTokenOneToSixDigits;
23184 case 'S':
23185 if (strict) { return parseTokenOneDigit; }
23186 /* falls through */
23187 case 'SS':
23188 if (strict) { return parseTokenTwoDigits; }
23189 /* falls through */
23190 case 'SSS':
23191 if (strict) { return parseTokenThreeDigits; }
23192 /* falls through */
23193 case 'DDD':
23194 return parseTokenOneToThreeDigits;
23195 case 'MMM':
23196 case 'MMMM':
23197 case 'dd':
23198 case 'ddd':
23199 case 'dddd':
23200 return parseTokenWord;
23201 case 'a':
23202 case 'A':
23203 return getLangDefinition(config._l)._meridiemParse;
23204 case 'X':
23205 return parseTokenTimestampMs;
23206 case 'Z':
23207 case 'ZZ':
23208 return parseTokenTimezone;
23209 case 'T':
23210 return parseTokenT;
23211 case 'SSSS':
23212 return parseTokenDigits;
23213 case 'MM':
23214 case 'DD':
23215 case 'YY':
23216 case 'GG':
23217 case 'gg':
23218 case 'HH':
23219 case 'hh':
23220 case 'mm':
23221 case 'ss':
23222 case 'ww':
23223 case 'WW':
23224 return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits;
23225 case 'M':
23226 case 'D':
23227 case 'd':
23228 case 'H':
23229 case 'h':
23230 case 'm':
23231 case 's':
23232 case 'w':
23233 case 'W':
23234 case 'e':
23235 case 'E':
23236 return parseTokenOneOrTwoDigits;
23237 default :
23238 a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i"));
23239 return a;
23240 }
23241 }
23242
23243 function timezoneMinutesFromString(string) {
23244 string = string || "";
23245 var possibleTzMatches = (string.match(parseTokenTimezone) || []),
23246 tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [],
23247 parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0],
23248 minutes = +(parts[1] * 60) + toInt(parts[2]);
23249
23250 return parts[0] === '+' ? -minutes : minutes;
23251 }
23252
23253 // function to convert string input to date
23254 function addTimeToArrayFromToken(token, input, config) {
23255 var a, datePartArray = config._a;
23256
23257 switch (token) {
23258 // MONTH
23259 case 'M' : // fall through to MM
23260 case 'MM' :
23261 if (input != null) {
23262 datePartArray[MONTH] = toInt(input) - 1;
23263 }
23264 break;
23265 case 'MMM' : // fall through to MMMM
23266 case 'MMMM' :
23267 a = getLangDefinition(config._l).monthsParse(input);
23268 // if we didn't find a month name, mark the date as invalid.
23269 if (a != null) {
23270 datePartArray[MONTH] = a;
23271 } else {
23272 config._pf.invalidMonth = input;
23273 }
23274 break;
23275 // DAY OF MONTH
23276 case 'D' : // fall through to DD
23277 case 'DD' :
23278 if (input != null) {
23279 datePartArray[DATE] = toInt(input);
23280 }
23281 break;
23282 // DAY OF YEAR
23283 case 'DDD' : // fall through to DDDD
23284 case 'DDDD' :
23285 if (input != null) {
23286 config._dayOfYear = toInt(input);
23287 }
23288
23289 break;
23290 // YEAR
23291 case 'YY' :
23292 datePartArray[YEAR] = toInt(input) + (toInt(input) > 68 ? 1900 : 2000);
23293 break;
23294 case 'YYYY' :
23295 case 'YYYYY' :
23296 case 'YYYYYY' :
23297 datePartArray[YEAR] = toInt(input);
23298 break;
23299 // AM / PM
23300 case 'a' : // fall through to A
23301 case 'A' :
23302 config._isPm = getLangDefinition(config._l).isPM(input);
23303 break;
23304 // 24 HOUR
23305 case 'H' : // fall through to hh
23306 case 'HH' : // fall through to hh
23307 case 'h' : // fall through to hh
23308 case 'hh' :
23309 datePartArray[HOUR] = toInt(input);
23310 break;
23311 // MINUTE
23312 case 'm' : // fall through to mm
23313 case 'mm' :
23314 datePartArray[MINUTE] = toInt(input);
23315 break;
23316 // SECOND
23317 case 's' : // fall through to ss
23318 case 'ss' :
23319 datePartArray[SECOND] = toInt(input);
23320 break;
23321 // MILLISECOND
23322 case 'S' :
23323 case 'SS' :
23324 case 'SSS' :
23325 case 'SSSS' :
23326 datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
23327 break;
23328 // UNIX TIMESTAMP WITH MS
23329 case 'X':
23330 config._d = new Date(parseFloat(input) * 1000);
23331 break;
23332 // TIMEZONE
23333 case 'Z' : // fall through to ZZ
23334 case 'ZZ' :
23335 config._useUTC = true;
23336 config._tzm = timezoneMinutesFromString(input);
23337 break;
23338 case 'w':
23339 case 'ww':
23340 case 'W':
23341 case 'WW':
23342 case 'd':
23343 case 'dd':
23344 case 'ddd':
23345 case 'dddd':
23346 case 'e':
23347 case 'E':
23348 token = token.substr(0, 1);
23349 /* falls through */
23350 case 'gg':
23351 case 'gggg':
23352 case 'GG':
23353 case 'GGGG':
23354 case 'GGGGG':
23355 token = token.substr(0, 2);
23356 if (input) {
23357 config._w = config._w || {};
23358 config._w[token] = input;
23359 }
23360 break;
23361 }
23362 }
23363
23364 // convert an array to a date.
23365 // the array should mirror the parameters below
23366 // note: all values past the year are optional and will default to the lowest possible value.
23367 // [year, month, day , hour, minute, second, millisecond]
23368 function dateFromConfig(config) {
23369 var i, date, input = [], currentDate,
23370 yearToUse, fixYear, w, temp, lang, weekday, week;
23371
23372 if (config._d) {
23373 return;
23374 }
23375
23376 currentDate = currentDateArray(config);
23377
23378 //compute day of the year from weeks and weekdays
23379 if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {
23380 fixYear = function (val) {
23381 var int_val = parseInt(val, 10);
23382 return val ?
23383 (val.length < 3 ? (int_val > 68 ? 1900 + int_val : 2000 + int_val) : int_val) :
23384 (config._a[YEAR] == null ? moment().weekYear() : config._a[YEAR]);
23385 };
23386
23387 w = config._w;
23388 if (w.GG != null || w.W != null || w.E != null) {
23389 temp = dayOfYearFromWeeks(fixYear(w.GG), w.W || 1, w.E, 4, 1);
23390 }
23391 else {
23392 lang = getLangDefinition(config._l);
23393 weekday = w.d != null ? parseWeekday(w.d, lang) :
23394 (w.e != null ? parseInt(w.e, 10) + lang._week.dow : 0);
23395
23396 week = parseInt(w.w, 10) || 1;
23397
23398 //if we're parsing 'd', then the low day numbers may be next week
23399 if (w.d != null && weekday < lang._week.dow) {
23400 week++;
23401 }
23402
23403 temp = dayOfYearFromWeeks(fixYear(w.gg), week, weekday, lang._week.doy, lang._week.dow);
23404 }
23405
23406 config._a[YEAR] = temp.year;
23407 config._dayOfYear = temp.dayOfYear;
23408 }
23409
23410 //if the day of the year is set, figure out what it is
23411 if (config._dayOfYear) {
23412 yearToUse = config._a[YEAR] == null ? currentDate[YEAR] : config._a[YEAR];
23413
23414 if (config._dayOfYear > daysInYear(yearToUse)) {
23415 config._pf._overflowDayOfYear = true;
23416 }
23417
23418 date = makeUTCDate(yearToUse, 0, config._dayOfYear);
23419 config._a[MONTH] = date.getUTCMonth();
23420 config._a[DATE] = date.getUTCDate();
23421 }
23422
23423 // Default to current date.
23424 // * if no year, month, day of month are given, default to today
23425 // * if day of month is given, default month and year
23426 // * if month is given, default only year
23427 // * if year is given, don't default anything
23428 for (i = 0; i < 3 && config._a[i] == null; ++i) {
23429 config._a[i] = input[i] = currentDate[i];
23430 }
23431
23432 // Zero out whatever was not defaulted, including time
23433 for (; i < 7; i++) {
23434 config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
23435 }
23436
23437 // add the offsets to the time to be parsed so that we can have a clean array for checking isValid
23438 input[HOUR] += toInt((config._tzm || 0) / 60);
23439 input[MINUTE] += toInt((config._tzm || 0) % 60);
23440
23441 config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
23442 }
23443
23444 function dateFromObject(config) {
23445 var normalizedInput;
23446
23447 if (config._d) {
23448 return;
23449 }
23450
23451 normalizedInput = normalizeObjectUnits(config._i);
23452 config._a = [
23453 normalizedInput.year,
23454 normalizedInput.month,
23455 normalizedInput.day,
23456 normalizedInput.hour,
23457 normalizedInput.minute,
23458 normalizedInput.second,
23459 normalizedInput.millisecond
23460 ];
23461
23462 dateFromConfig(config);
23463 }
23464
23465 function currentDateArray(config) {
23466 var now = new Date();
23467 if (config._useUTC) {
23468 return [
23469 now.getUTCFullYear(),
23470 now.getUTCMonth(),
23471 now.getUTCDate()
23472 ];
23473 } else {
23474 return [now.getFullYear(), now.getMonth(), now.getDate()];
23475 }
23476 }
23477
23478 // date from string and format string
23479 function makeDateFromStringAndFormat(config) {
23480
23481 config._a = [];
23482 config._pf.empty = true;
23483
23484 // This array is used to make a Date, either with `new Date` or `Date.UTC`
23485 var lang = getLangDefinition(config._l),
23486 string = '' + config._i,
23487 i, parsedInput, tokens, token, skipped,
23488 stringLength = string.length,
23489 totalParsedInputLength = 0;
23490
23491 tokens = expandFormat(config._f, lang).match(formattingTokens) || [];
23492
23493 for (i = 0; i < tokens.length; i++) {
23494 token = tokens[i];
23495 parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];
23496 if (parsedInput) {
23497 skipped = string.substr(0, string.indexOf(parsedInput));
23498 if (skipped.length > 0) {
23499 config._pf.unusedInput.push(skipped);
23500 }
23501 string = string.slice(string.indexOf(parsedInput) + parsedInput.length);
23502 totalParsedInputLength += parsedInput.length;
23503 }
23504 // don't parse if it's not a known token
23505 if (formatTokenFunctions[token]) {
23506 if (parsedInput) {
23507 config._pf.empty = false;
23508 }
23509 else {
23510 config._pf.unusedTokens.push(token);
23511 }
23512 addTimeToArrayFromToken(token, parsedInput, config);
23513 }
23514 else if (config._strict && !parsedInput) {
23515 config._pf.unusedTokens.push(token);
23516 }
23517 }
23518
23519 // add remaining unparsed input length to the string
23520 config._pf.charsLeftOver = stringLength - totalParsedInputLength;
23521 if (string.length > 0) {
23522 config._pf.unusedInput.push(string);
23523 }
23524
23525 // handle am pm
23526 if (config._isPm && config._a[HOUR] < 12) {
23527 config._a[HOUR] += 12;
23528 }
23529 // if is 12 am, change hours to 0
23530 if (config._isPm === false && config._a[HOUR] === 12) {
23531 config._a[HOUR] = 0;
23532 }
23533
23534 dateFromConfig(config);
23535 checkOverflow(config);
23536 }
23537
23538 function unescapeFormat(s) {
23539 return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {
23540 return p1 || p2 || p3 || p4;
23541 });
23542 }
23543
23544 // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
23545 function regexpEscape(s) {
23546 return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
23547 }
23548
23549 // date from string and array of format strings
23550 function makeDateFromStringAndArray(config) {
23551 var tempConfig,
23552 bestMoment,
23553
23554 scoreToBeat,
23555 i,
23556 currentScore;
23557
23558 if (config._f.length === 0) {
23559 config._pf.invalidFormat = true;
23560 config._d = new Date(NaN);
23561 return;
23562 }
23563
23564 for (i = 0; i < config._f.length; i++) {
23565 currentScore = 0;
23566 tempConfig = extend({}, config);
23567 tempConfig._pf = defaultParsingFlags();
23568 tempConfig._f = config._f[i];
23569 makeDateFromStringAndFormat(tempConfig);
23570
23571 if (!isValid(tempConfig)) {
23572 continue;
23573 }
23574
23575 // if there is any input that was not parsed add a penalty for that format
23576 currentScore += tempConfig._pf.charsLeftOver;
23577
23578 //or tokens
23579 currentScore += tempConfig._pf.unusedTokens.length * 10;
23580
23581 tempConfig._pf.score = currentScore;
23582
23583 if (scoreToBeat == null || currentScore < scoreToBeat) {
23584 scoreToBeat = currentScore;
23585 bestMoment = tempConfig;
23586 }
23587 }
23588
23589 extend(config, bestMoment || tempConfig);
23590 }
23591
23592 // date from iso format
23593 function makeDateFromString(config) {
23594 var i, l,
23595 string = config._i,
23596 match = isoRegex.exec(string);
23597
23598 if (match) {
23599 config._pf.iso = true;
23600 for (i = 0, l = isoDates.length; i < l; i++) {
23601 if (isoDates[i][1].exec(string)) {
23602 // match[5] should be "T" or undefined
23603 config._f = isoDates[i][0] + (match[6] || " ");
23604 break;
23605 }
23606 }
23607 for (i = 0, l = isoTimes.length; i < l; i++) {
23608 if (isoTimes[i][1].exec(string)) {
23609 config._f += isoTimes[i][0];
23610 break;
23611 }
23612 }
23613 if (string.match(parseTokenTimezone)) {
23614 config._f += "Z";
23615 }
23616 makeDateFromStringAndFormat(config);
23617 }
23618 else {
23619 config._d = new Date(string);
23620 }
23621 }
23622
23623 function makeDateFromInput(config) {
23624 var input = config._i,
23625 matched = aspNetJsonRegex.exec(input);
23626
23627 if (input === undefined) {
23628 config._d = new Date();
23629 } else if (matched) {
23630 config._d = new Date(+matched[1]);
23631 } else if (typeof input === 'string') {
23632 makeDateFromString(config);
23633 } else if (isArray(input)) {
23634 config._a = input.slice(0);
23635 dateFromConfig(config);
23636 } else if (isDate(input)) {
23637 config._d = new Date(+input);
23638 } else if (typeof(input) === 'object') {
23639 dateFromObject(config);
23640 } else {
23641 config._d = new Date(input);
23642 }
23643 }
23644
23645 function makeDate(y, m, d, h, M, s, ms) {
23646 //can't just apply() to create a date:
23647 //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply
23648 var date = new Date(y, m, d, h, M, s, ms);
23649
23650 //the date constructor doesn't accept years < 1970
23651 if (y < 1970) {
23652 date.setFullYear(y);
23653 }
23654 return date;
23655 }
23656
23657 function makeUTCDate(y) {
23658 var date = new Date(Date.UTC.apply(null, arguments));
23659 if (y < 1970) {
23660 date.setUTCFullYear(y);
23661 }
23662 return date;
23663 }
23664
23665 function parseWeekday(input, language) {
23666 if (typeof input === 'string') {
23667 if (!isNaN(input)) {
23668 input = parseInt(input, 10);
23669 }
23670 else {
23671 input = language.weekdaysParse(input);
23672 if (typeof input !== 'number') {
23673 return null;
23674 }
23675 }
23676 }
23677 return input;
23678 }
23679
23680 /************************************
23681 Relative Time
23682 ************************************/
23683
23684
23685 // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize
23686 function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) {
23687 return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture);
23688 }
23689
23690 function relativeTime(milliseconds, withoutSuffix, lang) {
23691 var seconds = round(Math.abs(milliseconds) / 1000),
23692 minutes = round(seconds / 60),
23693 hours = round(minutes / 60),
23694 days = round(hours / 24),
23695 years = round(days / 365),
23696 args = seconds < 45 && ['s', seconds] ||
23697 minutes === 1 && ['m'] ||
23698 minutes < 45 && ['mm', minutes] ||
23699 hours === 1 && ['h'] ||
23700 hours < 22 && ['hh', hours] ||
23701 days === 1 && ['d'] ||
23702 days <= 25 && ['dd', days] ||
23703 days <= 45 && ['M'] ||
23704 days < 345 && ['MM', round(days / 30)] ||
23705 years === 1 && ['y'] || ['yy', years];
23706 args[2] = withoutSuffix;
23707 args[3] = milliseconds > 0;
23708 args[4] = lang;
23709 return substituteTimeAgo.apply({}, args);
23710 }
23711
23712
23713 /************************************
23714 Week of Year
23715 ************************************/
23716
23717
23718 // firstDayOfWeek 0 = sun, 6 = sat
23719 // the day of the week that starts the week
23720 // (usually sunday or monday)
23721 // firstDayOfWeekOfYear 0 = sun, 6 = sat
23722 // the first week is the week that contains the first
23723 // of this day of the week
23724 // (eg. ISO weeks use thursday (4))
23725 function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) {
23726 var end = firstDayOfWeekOfYear - firstDayOfWeek,
23727 daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(),
23728 adjustedMoment;
23729
23730
23731 if (daysToDayOfWeek > end) {
23732 daysToDayOfWeek -= 7;
23733 }
23734
23735 if (daysToDayOfWeek < end - 7) {
23736 daysToDayOfWeek += 7;
23737 }
23738
23739 adjustedMoment = moment(mom).add('d', daysToDayOfWeek);
23740 return {
23741 week: Math.ceil(adjustedMoment.dayOfYear() / 7),
23742 year: adjustedMoment.year()
23743 };
23744 }
23745
23746 //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
23747 function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) {
23748 var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear;
23749
23750 weekday = weekday != null ? weekday : firstDayOfWeek;
23751 daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0);
23752 dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1;
23753
23754 return {
23755 year: dayOfYear > 0 ? year : year - 1,
23756 dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear
23757 };
23758 }
23759
23760 /************************************
23761 Top Level Functions
23762 ************************************/
23763
23764 function makeMoment(config) {
23765 var input = config._i,
23766 format = config._f;
23767
23768 if (input === null) {
23769 return moment.invalid({nullInput: true});
23770 }
23771
23772 if (typeof input === 'string') {
23773 config._i = input = getLangDefinition().preparse(input);
23774 }
23775
23776 if (moment.isMoment(input)) {
23777 config = cloneMoment(input);
23778
23779 config._d = new Date(+input._d);
23780 } else if (format) {
23781 if (isArray(format)) {
23782 makeDateFromStringAndArray(config);
23783 } else {
23784 makeDateFromStringAndFormat(config);
23785 }
23786 } else {
23787 makeDateFromInput(config);
23788 }
23789
23790 return new Moment(config);
23791 }
23792
23793 moment = function (input, format, lang, strict) {
23794 var c;
23795
23796 if (typeof(lang) === "boolean") {
23797 strict = lang;
23798 lang = undefined;
23799 }
23800 // object construction must be done this way.
23801 // https://github.com/moment/moment/issues/1423
23802 c = {};
23803 c._isAMomentObject = true;
23804 c._i = input;
23805 c._f = format;
23806 c._l = lang;
23807 c._strict = strict;
23808 c._isUTC = false;
23809 c._pf = defaultParsingFlags();
23810
23811 return makeMoment(c);
23812 };
23813
23814 // creating with utc
23815 moment.utc = function (input, format, lang, strict) {
23816 var c;
23817
23818 if (typeof(lang) === "boolean") {
23819 strict = lang;
23820 lang = undefined;
23821 }
23822 // object construction must be done this way.
23823 // https://github.com/moment/moment/issues/1423
23824 c = {};
23825 c._isAMomentObject = true;
23826 c._useUTC = true;
23827 c._isUTC = true;
23828 c._l = lang;
23829 c._i = input;
23830 c._f = format;
23831 c._strict = strict;
23832 c._pf = defaultParsingFlags();
23833
23834 return makeMoment(c).utc();
23835 };
23836
23837 // creating with unix timestamp (in seconds)
23838 moment.unix = function (input) {
23839 return moment(input * 1000);
23840 };
23841
23842 // duration
23843 moment.duration = function (input, key) {
23844 var duration = input,
23845 // matching against regexp is expensive, do it on demand
23846 match = null,
23847 sign,
23848 ret,
23849 parseIso;
23850
23851 if (moment.isDuration(input)) {
23852 duration = {
23853 ms: input._milliseconds,
23854 d: input._days,
23855 M: input._months
23856 };
23857 } else if (typeof input === 'number') {
23858 duration = {};
23859 if (key) {
23860 duration[key] = input;
23861 } else {
23862 duration.milliseconds = input;
23863 }
23864 } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) {
23865 sign = (match[1] === "-") ? -1 : 1;
23866 duration = {
23867 y: 0,
23868 d: toInt(match[DATE]) * sign,
23869 h: toInt(match[HOUR]) * sign,
23870 m: toInt(match[MINUTE]) * sign,
23871 s: toInt(match[SECOND]) * sign,
23872 ms: toInt(match[MILLISECOND]) * sign
23873 };
23874 } else if (!!(match = isoDurationRegex.exec(input))) {
23875 sign = (match[1] === "-") ? -1 : 1;
23876 parseIso = function (inp) {
23877 // We'd normally use ~~inp for this, but unfortunately it also
23878 // converts floats to ints.
23879 // inp may be undefined, so careful calling replace on it.
23880 var res = inp && parseFloat(inp.replace(',', '.'));
23881 // apply sign while we're at it
23882 return (isNaN(res) ? 0 : res) * sign;
23883 };
23884 duration = {
23885 y: parseIso(match[2]),
23886 M: parseIso(match[3]),
23887 d: parseIso(match[4]),
23888 h: parseIso(match[5]),
23889 m: parseIso(match[6]),
23890 s: parseIso(match[7]),
23891 w: parseIso(match[8])
23892 };
23893 }
23894
23895 ret = new Duration(duration);
23896
23897 if (moment.isDuration(input) && input.hasOwnProperty('_lang')) {
23898 ret._lang = input._lang;
23899 }
23900
23901 return ret;
23902 };
23903
23904 // version number
23905 moment.version = VERSION;
23906
23907 // default format
23908 moment.defaultFormat = isoFormat;
23909
23910 // This function will be called whenever a moment is mutated.
23911 // It is intended to keep the offset in sync with the timezone.
23912 moment.updateOffset = function () {};
23913
23914 // This function will load languages and then set the global language. If
23915 // no arguments are passed in, it will simply return the current global
23916 // language key.
23917 moment.lang = function (key, values) {
23918 var r;
23919 if (!key) {
23920 return moment.fn._lang._abbr;
23921 }
23922 if (values) {
23923 loadLang(normalizeLanguage(key), values);
23924 } else if (values === null) {
23925 unloadLang(key);
23926 key = 'en';
23927 } else if (!languages[key]) {
23928 getLangDefinition(key);
23929 }
23930 r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key);
23931 return r._abbr;
23932 };
23933
23934 // returns language data
23935 moment.langData = function (key) {
23936 if (key && key._lang && key._lang._abbr) {
23937 key = key._lang._abbr;
23938 }
23939 return getLangDefinition(key);
23940 };
23941
23942 // compare moment object
23943 moment.isMoment = function (obj) {
23944 return obj instanceof Moment ||
23945 (obj != null && obj.hasOwnProperty('_isAMomentObject'));
23946 };
23947
23948 // for typechecking Duration objects
23949 moment.isDuration = function (obj) {
23950 return obj instanceof Duration;
23951 };
23952
23953 for (i = lists.length - 1; i >= 0; --i) {
23954 makeList(lists[i]);
23955 }
23956
23957 moment.normalizeUnits = function (units) {
23958 return normalizeUnits(units);
23959 };
23960
23961 moment.invalid = function (flags) {
23962 var m = moment.utc(NaN);
23963 if (flags != null) {
23964 extend(m._pf, flags);
23965 }
23966 else {
23967 m._pf.userInvalidated = true;
23968 }
23969
23970 return m;
23971 };
23972
23973 moment.parseZone = function (input) {
23974 return moment(input).parseZone();
23975 };
23976
23977 /************************************
23978 Moment Prototype
23979 ************************************/
23980
23981
23982 extend(moment.fn = Moment.prototype, {
23983
23984 clone : function () {
23985 return moment(this);
23986 },
23987
23988 valueOf : function () {
23989 return +this._d + ((this._offset || 0) * 60000);
23990 },
23991
23992 unix : function () {
23993 return Math.floor(+this / 1000);
23994 },
23995
23996 toString : function () {
23997 return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ");
23998 },
23999
24000 toDate : function () {
24001 return this._offset ? new Date(+this) : this._d;
24002 },
24003
24004 toISOString : function () {
24005 var m = moment(this).utc();
24006 if (0 < m.year() && m.year() <= 9999) {
24007 return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
24008 } else {
24009 return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
24010 }
24011 },
24012
24013 toArray : function () {
24014 var m = this;
24015 return [
24016 m.year(),
24017 m.month(),
24018 m.date(),
24019 m.hours(),
24020 m.minutes(),
24021 m.seconds(),
24022 m.milliseconds()
24023 ];
24024 },
24025
24026 isValid : function () {
24027 return isValid(this);
24028 },
24029
24030 isDSTShifted : function () {
24031
24032 if (this._a) {
24033 return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0;
24034 }
24035
24036 return false;
24037 },
24038
24039 parsingFlags : function () {
24040 return extend({}, this._pf);
24041 },
24042
24043 invalidAt: function () {
24044 return this._pf.overflow;
24045 },
24046
24047 utc : function () {
24048 return this.zone(0);
24049 },
24050
24051 local : function () {
24052 this.zone(0);
24053 this._isUTC = false;
24054 return this;
24055 },
24056
24057 format : function (inputString) {
24058 var output = formatMoment(this, inputString || moment.defaultFormat);
24059 return this.lang().postformat(output);
24060 },
24061
24062 add : function (input, val) {
24063 var dur;
24064 // switch args to support add('s', 1) and add(1, 's')
24065 if (typeof input === 'string') {
24066 dur = moment.duration(+val, input);
24067 } else {
24068 dur = moment.duration(input, val);
24069 }
24070 addOrSubtractDurationFromMoment(this, dur, 1);
24071 return this;
24072 },
24073
24074 subtract : function (input, val) {
24075 var dur;
24076 // switch args to support subtract('s', 1) and subtract(1, 's')
24077 if (typeof input === 'string') {
24078 dur = moment.duration(+val, input);
24079 } else {
24080 dur = moment.duration(input, val);
24081 }
24082 addOrSubtractDurationFromMoment(this, dur, -1);
24083 return this;
24084 },
24085
24086 diff : function (input, units, asFloat) {
24087 var that = makeAs(input, this),
24088 zoneDiff = (this.zone() - that.zone()) * 6e4,
24089 diff, output;
24090
24091 units = normalizeUnits(units);
24092
24093 if (units === 'year' || units === 'month') {
24094 // average number of days in the months in the given dates
24095 diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2
24096 // difference in months
24097 output = ((this.year() - that.year()) * 12) + (this.month() - that.month());
24098 // adjust by taking difference in days, average number of days
24099 // and dst in the given months.
24100 output += ((this - moment(this).startOf('month')) -
24101 (that - moment(that).startOf('month'))) / diff;
24102 // same as above but with zones, to negate all dst
24103 output -= ((this.zone() - moment(this).startOf('month').zone()) -
24104 (that.zone() - moment(that).startOf('month').zone())) * 6e4 / diff;
24105 if (units === 'year') {
24106 output = output / 12;
24107 }
24108 } else {
24109 diff = (this - that);
24110 output = units === 'second' ? diff / 1e3 : // 1000
24111 units === 'minute' ? diff / 6e4 : // 1000 * 60
24112 units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60
24113 units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst
24114 units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst
24115 diff;
24116 }
24117 return asFloat ? output : absRound(output);
24118 },
24119
24120 from : function (time, withoutSuffix) {
24121 return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix);
24122 },
24123
24124 fromNow : function (withoutSuffix) {
24125 return this.from(moment(), withoutSuffix);
24126 },
24127
24128 calendar : function () {
24129 // We want to compare the start of today, vs this.
24130 // Getting start-of-today depends on whether we're zone'd or not.
24131 var sod = makeAs(moment(), this).startOf('day'),
24132 diff = this.diff(sod, 'days', true),
24133 format = diff < -6 ? 'sameElse' :
24134 diff < -1 ? 'lastWeek' :
24135 diff < 0 ? 'lastDay' :
24136 diff < 1 ? 'sameDay' :
24137 diff < 2 ? 'nextDay' :
24138 diff < 7 ? 'nextWeek' : 'sameElse';
24139 return this.format(this.lang().calendar(format, this));
24140 },
24141
24142 isLeapYear : function () {
24143 return isLeapYear(this.year());
24144 },
24145
24146 isDST : function () {
24147 return (this.zone() < this.clone().month(0).zone() ||
24148 this.zone() < this.clone().month(5).zone());
24149 },
24150
24151 day : function (input) {
24152 var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();
24153 if (input != null) {
24154 input = parseWeekday(input, this.lang());
24155 return this.add({ d : input - day });
24156 } else {
24157 return day;
24158 }
24159 },
24160
24161 month : function (input) {
24162 var utc = this._isUTC ? 'UTC' : '',
24163 dayOfMonth;
24164
24165 if (input != null) {
24166 if (typeof input === 'string') {
24167 input = this.lang().monthsParse(input);
24168 if (typeof input !== 'number') {
24169 return this;
24170 }
24171 }
24172
24173 dayOfMonth = this.date();
24174 this.date(1);
24175 this._d['set' + utc + 'Month'](input);
24176 this.date(Math.min(dayOfMonth, this.daysInMonth()));
24177
24178 moment.updateOffset(this);
24179 return this;
24180 } else {
24181 return this._d['get' + utc + 'Month']();
24182 }
24183 },
24184
24185 startOf: function (units) {
24186 units = normalizeUnits(units);
24187 // the following switch intentionally omits break keywords
24188 // to utilize falling through the cases.
24189 switch (units) {
24190 case 'year':
24191 this.month(0);
24192 /* falls through */
24193 case 'month':
24194 this.date(1);
24195 /* falls through */
24196 case 'week':
24197 case 'isoWeek':
24198 case 'day':
24199 this.hours(0);
24200 /* falls through */
24201 case 'hour':
24202 this.minutes(0);
24203 /* falls through */
24204 case 'minute':
24205 this.seconds(0);
24206 /* falls through */
24207 case 'second':
24208 this.milliseconds(0);
24209 /* falls through */
24210 }
24211
24212 // weeks are a special case
24213 if (units === 'week') {
24214 this.weekday(0);
24215 } else if (units === 'isoWeek') {
24216 this.isoWeekday(1);
24217 }
24218
24219 return this;
24220 },
24221
24222 endOf: function (units) {
24223 units = normalizeUnits(units);
24224 return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1);
24225 },
24226
24227 isAfter: function (input, units) {
24228 units = typeof units !== 'undefined' ? units : 'millisecond';
24229 return +this.clone().startOf(units) > +moment(input).startOf(units);
24230 },
24231
24232 isBefore: function (input, units) {
24233 units = typeof units !== 'undefined' ? units : 'millisecond';
24234 return +this.clone().startOf(units) < +moment(input).startOf(units);
24235 },
24236
24237 isSame: function (input, units) {
24238 units = units || 'ms';
24239 return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
24240 },
24241
24242 min: function (other) {
24243 other = moment.apply(null, arguments);
24244 return other < this ? this : other;
24245 },
24246
24247 max: function (other) {
24248 other = moment.apply(null, arguments);
24249 return other > this ? this : other;
24250 },
24251
24252 zone : function (input) {
24253 var offset = this._offset || 0;
24254 if (input != null) {
24255 if (typeof input === "string") {
24256 input = timezoneMinutesFromString(input);
24257 }
24258 if (Math.abs(input) < 16) {
24259 input = input * 60;
24260 }
24261 this._offset = input;
24262 this._isUTC = true;
24263 if (offset !== input) {
24264 addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, true);
24265 }
24266 } else {
24267 return this._isUTC ? offset : this._d.getTimezoneOffset();
24268 }
24269 return this;
24270 },
24271
24272 zoneAbbr : function () {
24273 return this._isUTC ? "UTC" : "";
24274 },
24275
24276 zoneName : function () {
24277 return this._isUTC ? "Coordinated Universal Time" : "";
24278 },
24279
24280 parseZone : function () {
24281 if (this._tzm) {
24282 this.zone(this._tzm);
24283 } else if (typeof this._i === 'string') {
24284 this.zone(this._i);
24285 }
24286 return this;
24287 },
24288
24289 hasAlignedHourOffset : function (input) {
24290 if (!input) {
24291 input = 0;
24292 }
24293 else {
24294 input = moment(input).zone();
24295 }
24296
24297 return (this.zone() - input) % 60 === 0;
24298 },
24299
24300 daysInMonth : function () {
24301 return daysInMonth(this.year(), this.month());
24302 },
24303
24304 dayOfYear : function (input) {
24305 var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1;
24306 return input == null ? dayOfYear : this.add("d", (input - dayOfYear));
24307 },
24308
24309 quarter : function () {
24310 return Math.ceil((this.month() + 1.0) / 3.0);
24311 },
24312
24313 weekYear : function (input) {
24314 var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year;
24315 return input == null ? year : this.add("y", (input - year));
24316 },
24317
24318 isoWeekYear : function (input) {
24319 var year = weekOfYear(this, 1, 4).year;
24320 return input == null ? year : this.add("y", (input - year));
24321 },
24322
24323 week : function (input) {
24324 var week = this.lang().week(this);
24325 return input == null ? week : this.add("d", (input - week) * 7);
24326 },
24327
24328 isoWeek : function (input) {
24329 var week = weekOfYear(this, 1, 4).week;
24330 return input == null ? week : this.add("d", (input - week) * 7);
24331 },
24332
24333 weekday : function (input) {
24334 var weekday = (this.day() + 7 - this.lang()._week.dow) % 7;
24335 return input == null ? weekday : this.add("d", input - weekday);
24336 },
24337
24338 isoWeekday : function (input) {
24339 // behaves the same as moment#day except
24340 // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)
24341 // as a setter, sunday should belong to the previous week.
24342 return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7);
24343 },
24344
24345 get : function (units) {
24346 units = normalizeUnits(units);
24347 return this[units]();
24348 },
24349
24350 set : function (units, value) {
24351 units = normalizeUnits(units);
24352 if (typeof this[units] === 'function') {
24353 this[units](value);
24354 }
24355 return this;
24356 },
24357
24358 // If passed a language key, it will set the language for this
24359 // instance. Otherwise, it will return the language configuration
24360 // variables for this instance.
24361 lang : function (key) {
24362 if (key === undefined) {
24363 return this._lang;
24364 } else {
24365 this._lang = getLangDefinition(key);
24366 return this;
24367 }
24368 }
24369 });
24370
24371 // helper for adding shortcuts
24372 function makeGetterAndSetter(name, key) {
24373 moment.fn[name] = moment.fn[name + 's'] = function (input) {
24374 var utc = this._isUTC ? 'UTC' : '';
24375 if (input != null) {
24376 this._d['set' + utc + key](input);
24377 moment.updateOffset(this);
24378 return this;
24379 } else {
24380 return this._d['get' + utc + key]();
24381 }
24382 };
24383 }
24384
24385 // loop through and add shortcuts (Month, Date, Hours, Minutes, Seconds, Milliseconds)
24386 for (i = 0; i < proxyGettersAndSetters.length; i ++) {
24387 makeGetterAndSetter(proxyGettersAndSetters[i].toLowerCase().replace(/s$/, ''), proxyGettersAndSetters[i]);
24388 }
24389
24390 // add shortcut for year (uses different syntax than the getter/setter 'year' == 'FullYear')
24391 makeGetterAndSetter('year', 'FullYear');
24392
24393 // add plural methods
24394 moment.fn.days = moment.fn.day;
24395 moment.fn.months = moment.fn.month;
24396 moment.fn.weeks = moment.fn.week;
24397 moment.fn.isoWeeks = moment.fn.isoWeek;
24398
24399 // add aliased format methods
24400 moment.fn.toJSON = moment.fn.toISOString;
24401
24402 /************************************
24403 Duration Prototype
24404 ************************************/
24405
24406
24407 extend(moment.duration.fn = Duration.prototype, {
24408
24409 _bubble : function () {
24410 var milliseconds = this._milliseconds,
24411 days = this._days,
24412 months = this._months,
24413 data = this._data,
24414 seconds, minutes, hours, years;
24415
24416 // The following code bubbles up values, see the tests for
24417 // examples of what that means.
24418 data.milliseconds = milliseconds % 1000;
24419
24420 seconds = absRound(milliseconds / 1000);
24421 data.seconds = seconds % 60;
24422
24423 minutes = absRound(seconds / 60);
24424 data.minutes = minutes % 60;
24425
24426 hours = absRound(minutes / 60);
24427 data.hours = hours % 24;
24428
24429 days += absRound(hours / 24);
24430 data.days = days % 30;
24431
24432 months += absRound(days / 30);
24433 data.months = months % 12;
24434
24435 years = absRound(months / 12);
24436 data.years = years;
24437 },
24438
24439 weeks : function () {
24440 return absRound(this.days() / 7);
24441 },
24442
24443 valueOf : function () {
24444 return this._milliseconds +
24445 this._days * 864e5 +
24446 (this._months % 12) * 2592e6 +
24447 toInt(this._months / 12) * 31536e6;
24448 },
24449
24450 humanize : function (withSuffix) {
24451 var difference = +this,
24452 output = relativeTime(difference, !withSuffix, this.lang());
24453
24454 if (withSuffix) {
24455 output = this.lang().pastFuture(difference, output);
24456 }
24457
24458 return this.lang().postformat(output);
24459 },
24460
24461 add : function (input, val) {
24462 // supports only 2.0-style add(1, 's') or add(moment)
24463 var dur = moment.duration(input, val);
24464
24465 this._milliseconds += dur._milliseconds;
24466 this._days += dur._days;
24467 this._months += dur._months;
24468
24469 this._bubble();
24470
24471 return this;
24472 },
24473
24474 subtract : function (input, val) {
24475 var dur = moment.duration(input, val);
24476
24477 this._milliseconds -= dur._milliseconds;
24478 this._days -= dur._days;
24479 this._months -= dur._months;
24480
24481 this._bubble();
24482
24483 return this;
24484 },
24485
24486 get : function (units) {
24487 units = normalizeUnits(units);
24488 return this[units.toLowerCase() + 's']();
24489 },
24490
24491 as : function (units) {
24492 units = normalizeUnits(units);
24493 return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's']();
24494 },
24495
24496 lang : moment.fn.lang,
24497
24498 toIsoString : function () {
24499 // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js
24500 var years = Math.abs(this.years()),
24501 months = Math.abs(this.months()),
24502 days = Math.abs(this.days()),
24503 hours = Math.abs(this.hours()),
24504 minutes = Math.abs(this.minutes()),
24505 seconds = Math.abs(this.seconds() + this.milliseconds() / 1000);
24506
24507 if (!this.asSeconds()) {
24508 // this is the same as C#'s (Noda) and python (isodate)...
24509 // but not other JS (goog.date)
24510 return 'P0D';
24511 }
24512
24513 return (this.asSeconds() < 0 ? '-' : '') +
24514 'P' +
24515 (years ? years + 'Y' : '') +
24516 (months ? months + 'M' : '') +
24517 (days ? days + 'D' : '') +
24518 ((hours || minutes || seconds) ? 'T' : '') +
24519 (hours ? hours + 'H' : '') +
24520 (minutes ? minutes + 'M' : '') +
24521 (seconds ? seconds + 'S' : '');
24522 }
24523 });
24524
24525 function makeDurationGetter(name) {
24526 moment.duration.fn[name] = function () {
24527 return this._data[name];
24528 };
24529 }
24530
24531 function makeDurationAsGetter(name, factor) {
24532 moment.duration.fn['as' + name] = function () {
24533 return +this / factor;
24534 };
24535 }
24536
24537 for (i in unitMillisecondFactors) {
24538 if (unitMillisecondFactors.hasOwnProperty(i)) {
24539 makeDurationAsGetter(i, unitMillisecondFactors[i]);
24540 makeDurationGetter(i.toLowerCase());
24541 }
24542 }
24543
24544 makeDurationAsGetter('Weeks', 6048e5);
24545 moment.duration.fn.asMonths = function () {
24546 return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12;
24547 };
24548
24549
24550 /************************************
24551 Default Lang
24552 ************************************/
24553
24554
24555 // Set default language, other languages will inherit from English.
24556 moment.lang('en', {
24557 ordinal : function (number) {
24558 var b = number % 10,
24559 output = (toInt(number % 100 / 10) === 1) ? 'th' :
24560 (b === 1) ? 'st' :
24561 (b === 2) ? 'nd' :
24562 (b === 3) ? 'rd' : 'th';
24563 return number + output;
24564 }
24565 });
24566
24567 /* EMBED_LANGUAGES */
24568
24569 /************************************
24570 Exposing Moment
24571 ************************************/
24572
24573 function makeGlobal(deprecate) {
24574 var warned = false, local_moment = moment;
24575 /*global ender:false */
24576 if (typeof ender !== 'undefined') {
24577 return;
24578 }
24579 // here, `this` means `window` in the browser, or `global` on the server
24580 // add `moment` as a global object via a string identifier,
24581 // for Closure Compiler "advanced" mode
24582 if (deprecate) {
24583 global.moment = function () {
24584 if (!warned && console && console.warn) {
24585 warned = true;
24586 console.warn(
24587 "Accessing Moment through the global scope is " +
24588 "deprecated, and will be removed in an upcoming " +
24589 "release.");
24590 }
24591 return local_moment.apply(null, arguments);
24592 };
24593 extend(global.moment, local_moment);
24594 } else {
24595 global['moment'] = moment;
24596 }
24597 }
24598
24599 // CommonJS module is defined
24600 if (hasModule) {
24601 module.exports = moment;
24602 makeGlobal(true);
24603 } else if (typeof define === "function" && define.amd) {
24604 define("moment", function (require, exports, module) {
24605 if (module.config && module.config() && module.config().noGlobal !== true) {
24606 // If user provided noGlobal, he is aware of global
24607 makeGlobal(module.config().noGlobal === undefined);
24608 }
24609
24610 return moment;
24611 });
24612 } else {
24613 makeGlobal();
24614 }
24615 }).call(this);
24616 /*!
24617 * UCSV 1.1.0
24618 * Provided under MIT License.
24619 *
24620 * Copyright 2010-2012, Peter Johnson
24621 * http://www.uselesscode.org/javascript/csv/
24622 */
24623 var CSV=(function(){var f=/^\d+$/,g=/^\d*\.\d+$|^\d+\.\d*$/,i=/^\s|\s$|,|"|\n/,b=(function(){if(String.prototype.trim){return function(j){return j.trim()}}else{return function(j){return j.replace(/^\s*/,"").replace(/\s*$/,"")}}}());function h(j){return Object.prototype.toString.apply(j)==="[object Number]"}function a(j){return Object.prototype.toString.apply(j)==="[object String]"}function d(j){if(j.charAt(j.length-1)!=="\n"){return j}else{return j.substring(0,j.length-1)}}function e(k){var p,m="",o,n,l;for(n=0;n<k.length;n+=1){o=k[n];for(l=0;l<o.length;l+=1){p=o[l];if(a(p)){p=p.replace(/"/g,'""');if(i.test(p)||f.test(p)||g.test(p)){p='"'+p+'"'}else{if(p===""){p='""'}}}else{if(h(p)){p=p.toString(10)}else{if(p===null){p=""}else{p=p.toString()}}}m+=l<o.length-1?p+",":p}m+="\n"}return m}function c(t,p){t=d(t);var q="",l=false,m=false,o="",r=[],j=[],k,n;n=function(s){if(m!==true){if(s===""){s=null}else{if(p===true){s=b(s)}}if(f.test(s)){s=parseInt(s,10)}else{if(g.test(s)){s=parseFloat(s,10)}}}return s};for(k=0;k<t.length;k+=1){q=t.charAt(k);if(l===false&&(q===","||q==="\n")){o=n(o);r.push(o);if(q==="\n"){j.push(r);r=[]}o="";m=false}else{if(q!=='"'){o+=q}else{if(!l){l=true;m=true}else{if(t.charAt(k+1)==='"'){o+='"';k+=1}else{l=false}}}}}o=n(o);r.push(o);j.push(r);return j}if(typeof exports==="object"){exports.arrayToCsv=e;exports.csvToArray=c}return{arrayToCsv:e,csvToArray:c}}());
24624 /* Javascript plotting library for jQuery, version 0.8.2.
24625
24626 Copyright (c) 2007-2013 IOLA and Ole Laursen.
24627 Licensed under the MIT license.
24628
24629 */
24630
24631 // first an inline dependency, jquery.colorhelpers.js, we inline it here
24632 // for convenience
24633
24634 /* Plugin for jQuery for working with colors.
24635 *
24636 * Version 1.1.
24637 *
24638 * Inspiration from jQuery color animation plugin by John Resig.
24639 *
24640 * Released under the MIT license by Ole Laursen, October 2009.
24641 *
24642 * Examples:
24643 *
24644 * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
24645 * var c = $.color.extract($("#mydiv"), 'background-color');
24646 * console.log(c.r, c.g, c.b, c.a);
24647 * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
24648 *
24649 * Note that .scale() and .add() return the same modified object
24650 * instead of making a new one.
24651 *
24652 * V. 1.1: Fix error handling so e.g. parsing an empty string does
24653 * produce a color rather than just crashing.
24654 */
24655 (function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery);
24656
24657 // the actual Flot code
24658 (function($) {
24659
24660 // Cache the prototype hasOwnProperty for faster access
24661
24662 var hasOwnProperty = Object.prototype.hasOwnProperty;
24663
24664 ///////////////////////////////////////////////////////////////////////////
24665 // The Canvas object is a wrapper around an HTML5 <canvas> tag.
24666 //
24667 // @constructor
24668 // @param {string} cls List of classes to apply to the canvas.
24669 // @param {element} container Element onto which to append the canvas.
24670 //
24671 // Requiring a container is a little iffy, but unfortunately canvas
24672 // operations don't work unless the canvas is attached to the DOM.
24673
24674 function Canvas(cls, container) {
24675
24676 var element = container.children("." + cls)[0];
24677
24678 if (element == null) {
24679
24680 element = document.createElement("canvas");
24681 element.className = cls;
24682
24683 $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 })
24684 .appendTo(container);
24685
24686 // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas
24687
24688 if (!element.getContext) {
24689 if (window.G_vmlCanvasManager) {
24690 element = window.G_vmlCanvasManager.initElement(element);
24691 } else {
24692 throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");
24693 }
24694 }
24695 }
24696
24697 this.element = element;
24698
24699 var context = this.context = element.getContext("2d");
24700
24701 // Determine the screen's ratio of physical to device-independent
24702 // pixels. This is the ratio between the canvas width that the browser
24703 // advertises and the number of pixels actually present in that space.
24704
24705 // The iPhone 4, for example, has a device-independent width of 320px,
24706 // but its screen is actually 640px wide. It therefore has a pixel
24707 // ratio of 2, while most normal devices have a ratio of 1.
24708
24709 var devicePixelRatio = window.devicePixelRatio || 1,
24710 backingStoreRatio =
24711 context.webkitBackingStorePixelRatio ||
24712 context.mozBackingStorePixelRatio ||
24713 context.msBackingStorePixelRatio ||
24714 context.oBackingStorePixelRatio ||
24715 context.backingStorePixelRatio || 1;
24716
24717 this.pixelRatio = devicePixelRatio / backingStoreRatio;
24718
24719 // Size the canvas to match the internal dimensions of its container
24720
24721 this.resize(container.width(), container.height());
24722
24723 // Collection of HTML div layers for text overlaid onto the canvas
24724
24725 this.textContainer = null;
24726 this.text = {};
24727
24728 // Cache of text fragments and metrics, so we can avoid expensively
24729 // re-calculating them when the plot is re-rendered in a loop.
24730
24731 this._textCache = {};
24732 }
24733
24734 // Resizes the canvas to the given dimensions.
24735 //
24736 // @param {number} width New width of the canvas, in pixels.
24737 // @param {number} width New height of the canvas, in pixels.
24738
24739 Canvas.prototype.resize = function(width, height) {
24740
24741 if (width <= 0 || height <= 0) {
24742 throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height);
24743 }
24744
24745 var element = this.element,
24746 context = this.context,
24747 pixelRatio = this.pixelRatio;
24748
24749 // Resize the canvas, increasing its density based on the display's
24750 // pixel ratio; basically giving it more pixels without increasing the
24751 // size of its element, to take advantage of the fact that retina
24752 // displays have that many more pixels in the same advertised space.
24753
24754 // Resizing should reset the state (excanvas seems to be buggy though)
24755
24756 if (this.width != width) {
24757 element.width = width * pixelRatio;
24758 element.style.width = width + "px";
24759 this.width = width;
24760 }
24761
24762 if (this.height != height) {
24763 element.height = height * pixelRatio;
24764 element.style.height = height + "px";
24765 this.height = height;
24766 }
24767
24768 // Save the context, so we can reset in case we get replotted. The
24769 // restore ensure that we're really back at the initial state, and
24770 // should be safe even if we haven't saved the initial state yet.
24771
24772 context.restore();
24773 context.save();
24774
24775 // Scale the coordinate space to match the display density; so even though we
24776 // may have twice as many pixels, we still want lines and other drawing to
24777 // appear at the same size; the extra pixels will just make them crisper.
24778
24779 context.scale(pixelRatio, pixelRatio);
24780 };
24781
24782 // Clears the entire canvas area, not including any overlaid HTML text
24783
24784 Canvas.prototype.clear = function() {
24785 this.context.clearRect(0, 0, this.width, this.height);
24786 };
24787
24788 // Finishes rendering the canvas, including managing the text overlay.
24789
24790 Canvas.prototype.render = function() {
24791
24792 var cache = this._textCache;
24793
24794 // For each text layer, add elements marked as active that haven't
24795 // already been rendered, and remove those that are no longer active.
24796
24797 for (var layerKey in cache) {
24798 if (hasOwnProperty.call(cache, layerKey)) {
24799
24800 var layer = this.getTextLayer(layerKey),
24801 layerCache = cache[layerKey];
24802
24803 layer.hide();
24804
24805 for (var styleKey in layerCache) {
24806 if (hasOwnProperty.call(layerCache, styleKey)) {
24807 var styleCache = layerCache[styleKey];
24808 for (var key in styleCache) {
24809 if (hasOwnProperty.call(styleCache, key)) {
24810
24811 var positions = styleCache[key].positions;
24812
24813 for (var i = 0, position; position = positions[i]; i++) {
24814 if (position.active) {
24815 if (!position.rendered) {
24816 layer.append(position.element);
24817 position.rendered = true;
24818 }
24819 } else {
24820 positions.splice(i--, 1);
24821 if (position.rendered) {
24822 position.element.detach();
24823 }
24824 }
24825 }
24826
24827 if (positions.length == 0) {
24828 delete styleCache[key];
24829 }
24830 }
24831 }
24832 }
24833 }
24834
24835 layer.show();
24836 }
24837 }
24838 };
24839
24840 // Creates (if necessary) and returns the text overlay container.
24841 //
24842 // @param {string} classes String of space-separated CSS classes used to
24843 // uniquely identify the text layer.
24844 // @return {object} The jQuery-wrapped text-layer div.
24845
24846 Canvas.prototype.getTextLayer = function(classes) {
24847
24848 var layer = this.text[classes];
24849
24850 // Create the text layer if it doesn't exist
24851
24852 if (layer == null) {
24853
24854 // Create the text layer container, if it doesn't exist
24855
24856 if (this.textContainer == null) {
24857 this.textContainer = $("<div class='flot-text'></div>")
24858 .css({
24859 position: "absolute",
24860 top: 0,
24861 left: 0,
24862 bottom: 0,
24863 right: 0,
24864 'font-size': "smaller",
24865 color: "#545454"
24866 })
24867 .insertAfter(this.element);
24868 }
24869
24870 layer = this.text[classes] = $("<div></div>")
24871 .addClass(classes)
24872 .css({
24873 position: "absolute",
24874 top: 0,
24875 left: 0,
24876 bottom: 0,
24877 right: 0
24878 })
24879 .appendTo(this.textContainer);
24880 }
24881
24882 return layer;
24883 };
24884
24885 // Creates (if necessary) and returns a text info object.
24886 //
24887 // The object looks like this:
24888 //
24889 // {
24890 // width: Width of the text's wrapper div.
24891 // height: Height of the text's wrapper div.
24892 // element: The jQuery-wrapped HTML div containing the text.
24893 // positions: Array of positions at which this text is drawn.
24894 // }
24895 //
24896 // The positions array contains objects that look like this:
24897 //
24898 // {
24899 // active: Flag indicating whether the text should be visible.
24900 // rendered: Flag indicating whether the text is currently visible.
24901 // element: The jQuery-wrapped HTML div containing the text.
24902 // x: X coordinate at which to draw the text.
24903 // y: Y coordinate at which to draw the text.
24904 // }
24905 //
24906 // Each position after the first receives a clone of the original element.
24907 //
24908 // The idea is that that the width, height, and general 'identity' of the
24909 // text is constant no matter where it is placed; the placements are a
24910 // secondary property.
24911 //
24912 // Canvas maintains a cache of recently-used text info objects; getTextInfo
24913 // either returns the cached element or creates a new entry.
24914 //
24915 // @param {string} layer A string of space-separated CSS classes uniquely
24916 // identifying the layer containing this text.
24917 // @param {string} text Text string to retrieve info for.
24918 // @param {(string|object)=} font Either a string of space-separated CSS
24919 // classes or a font-spec object, defining the text's font and style.
24920 // @param {number=} angle Angle at which to rotate the text, in degrees.
24921 // Angle is currently unused, it will be implemented in the future.
24922 // @param {number=} width Maximum width of the text before it wraps.
24923 // @return {object} a text info object.
24924
24925 Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) {
24926
24927 var textStyle, layerCache, styleCache, info;
24928
24929 // Cast the value to a string, in case we were given a number or such
24930
24931 text = "" + text;
24932
24933 // If the font is a font-spec object, generate a CSS font definition
24934
24935 if (typeof font === "object") {
24936 textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family;
24937 } else {
24938 textStyle = font;
24939 }
24940
24941 // Retrieve (or create) the cache for the text's layer and styles
24942
24943 layerCache = this._textCache[layer];
24944
24945 if (layerCache == null) {
24946 layerCache = this._textCache[layer] = {};
24947 }
24948
24949 styleCache = layerCache[textStyle];
24950
24951 if (styleCache == null) {
24952 styleCache = layerCache[textStyle] = {};
24953 }
24954
24955 info = styleCache[text];
24956
24957 // If we can't find a matching element in our cache, create a new one
24958
24959 if (info == null) {
24960
24961 var element = $("<div></div>").html(text)
24962 .css({
24963 position: "absolute",
24964 'max-width': width,
24965 top: -9999
24966 })
24967 .appendTo(this.getTextLayer(layer));
24968
24969 if (typeof font === "object") {
24970 element.css({
24971 font: textStyle,
24972 color: font.color
24973 });
24974 } else if (typeof font === "string") {
24975 element.addClass(font);
24976 }
24977
24978 info = styleCache[text] = {
24979 width: element.outerWidth(true),
24980 height: element.outerHeight(true),
24981 element: element,
24982 positions: []
24983 };
24984
24985 element.detach();
24986 }
24987
24988 return info;
24989 };
24990
24991 // Adds a text string to the canvas text overlay.
24992 //
24993 // The text isn't drawn immediately; it is marked as rendering, which will
24994 // result in its addition to the canvas on the next render pass.
24995 //
24996 // @param {string} layer A string of space-separated CSS classes uniquely
24997 // identifying the layer containing this text.
24998 // @param {number} x X coordinate at which to draw the text.
24999 // @param {number} y Y coordinate at which to draw the text.
25000 // @param {string} text Text string to draw.
25001 // @param {(string|object)=} font Either a string of space-separated CSS
25002 // classes or a font-spec object, defining the text's font and style.
25003 // @param {number=} angle Angle at which to rotate the text, in degrees.
25004 // Angle is currently unused, it will be implemented in the future.
25005 // @param {number=} width Maximum width of the text before it wraps.
25006 // @param {string=} halign Horizontal alignment of the text; either "left",
25007 // "center" or "right".
25008 // @param {string=} valign Vertical alignment of the text; either "top",
25009 // "middle" or "bottom".
25010
25011 Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) {
25012
25013 var info = this.getTextInfo(layer, text, font, angle, width),
25014 positions = info.positions;
25015
25016 // Tweak the div's position to match the text's alignment
25017
25018 if (halign == "center") {
25019 x -= info.width / 2;
25020 } else if (halign == "right") {
25021 x -= info.width;
25022 }
25023
25024 if (valign == "middle") {
25025 y -= info.height / 2;
25026 } else if (valign == "bottom") {
25027 y -= info.height;
25028 }
25029
25030 // Determine whether this text already exists at this position.
25031 // If so, mark it for inclusion in the next render pass.
25032
25033 for (var i = 0, position; position = positions[i]; i++) {
25034 if (position.x == x && position.y == y) {
25035 position.active = true;
25036 return;
25037 }
25038 }
25039
25040 // If the text doesn't exist at this position, create a new entry
25041
25042 // For the very first position we'll re-use the original element,
25043 // while for subsequent ones we'll clone it.
25044
25045 position = {
25046 active: true,
25047 rendered: false,
25048 element: positions.length ? info.element.clone() : info.element,
25049 x: x,
25050 y: y
25051 };
25052
25053 positions.push(position);
25054
25055 // Move the element to its final position within the container
25056
25057 position.element.css({
25058 top: Math.round(y),
25059 left: Math.round(x),
25060 'text-align': halign // In case the text wraps
25061 });
25062 };
25063
25064 // Removes one or more text strings from the canvas text overlay.
25065 //
25066 // If no parameters are given, all text within the layer is removed.
25067 //
25068 // Note that the text is not immediately removed; it is simply marked as
25069 // inactive, which will result in its removal on the next render pass.
25070 // This avoids the performance penalty for 'clear and redraw' behavior,
25071 // where we potentially get rid of all text on a layer, but will likely
25072 // add back most or all of it later, as when redrawing axes, for example.
25073 //
25074 // @param {string} layer A string of space-separated CSS classes uniquely
25075 // identifying the layer containing this text.
25076 // @param {number=} x X coordinate of the text.
25077 // @param {number=} y Y coordinate of the text.
25078 // @param {string=} text Text string to remove.
25079 // @param {(string|object)=} font Either a string of space-separated CSS
25080 // classes or a font-spec object, defining the text's font and style.
25081 // @param {number=} angle Angle at which the text is rotated, in degrees.
25082 // Angle is currently unused, it will be implemented in the future.
25083
25084 Canvas.prototype.removeText = function(layer, x, y, text, font, angle) {
25085 if (text == null) {
25086 var layerCache = this._textCache[layer];
25087 if (layerCache != null) {
25088 for (var styleKey in layerCache) {
25089 if (hasOwnProperty.call(layerCache, styleKey)) {
25090 var styleCache = layerCache[styleKey];
25091 for (var key in styleCache) {
25092 if (hasOwnProperty.call(styleCache, key)) {
25093 var positions = styleCache[key].positions;
25094 for (var i = 0, position; position = positions[i]; i++) {
25095 position.active = false;
25096 }
25097 }
25098 }
25099 }
25100 }
25101 }
25102 } else {
25103 var positions = this.getTextInfo(layer, text, font, angle).positions;
25104 for (var i = 0, position; position = positions[i]; i++) {
25105 if (position.x == x && position.y == y) {
25106 position.active = false;
25107 }
25108 }
25109 }
25110 };
25111
25112 ///////////////////////////////////////////////////////////////////////////
25113 // The top-level container for the entire plot.
25114
25115 function Plot(placeholder, data_, options_, plugins) {
25116 // data is on the form:
25117 // [ series1, series2 ... ]
25118 // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
25119 // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
25120
25121 var series = [],
25122 options = {
25123 // the color theme used for graphs
25124 colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
25125 legend: {
25126 show: true,
25127 noColumns: 1, // number of colums in legend table
25128 labelFormatter: null, // fn: string -> string
25129 labelBoxBorderColor: "#ccc", // border color for the little label boxes
25130 container: null, // container (as jQuery object) to put legend in, null means default on top of graph
25131 position: "ne", // position of default legend container within plot
25132 margin: 5, // distance from grid edge to default legend container within plot
25133 backgroundColor: null, // null means auto-detect
25134 backgroundOpacity: 0.85, // set to 0 to avoid background
25135 sorted: null // default to no legend sorting
25136 },
25137 xaxis: {
25138 show: null, // null = auto-detect, true = always, false = never
25139 position: "bottom", // or "top"
25140 mode: null, // null or "time"
25141 font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" }
25142 color: null, // base color, labels, ticks
25143 tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
25144 transform: null, // null or f: number -> number to transform axis
25145 inverseTransform: null, // if transform is set, this should be the inverse function
25146 min: null, // min. value to show, null means set automatically
25147 max: null, // max. value to show, null means set automatically
25148 autoscaleMargin: null, // margin in % to add if auto-setting min/max
25149 ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
25150 tickFormatter: null, // fn: number -> string
25151 labelWidth: null, // size of tick labels in pixels
25152 labelHeight: null,
25153 reserveSpace: null, // whether to reserve space even if axis isn't shown
25154 tickLength: null, // size in pixels of ticks, or "full" for whole line
25155 alignTicksWithAxis: null, // axis number or null for no sync
25156 tickDecimals: null, // no. of decimals, null means auto
25157 tickSize: null, // number or [number, "unit"]
25158 minTickSize: null // number or [number, "unit"]
25159 },
25160 yaxis: {
25161 autoscaleMargin: 0.02,
25162 position: "left" // or "right"
25163 },
25164 xaxes: [],
25165 yaxes: [],
25166 series: {
25167 points: {
25168 show: false,
25169 radius: 3,
25170 lineWidth: 2, // in pixels
25171 fill: true,
25172 fillColor: "#ffffff",
25173 symbol: "circle" // or callback
25174 },
25175 lines: {
25176 // we don't put in show: false so we can see
25177 // whether lines were actively disabled
25178 lineWidth: 2, // in pixels
25179 fill: false,
25180 fillColor: null,
25181 steps: false
25182 // Omit 'zero', so we can later default its value to
25183 // match that of the 'fill' option.
25184 },
25185 bars: {
25186 show: false,
25187 lineWidth: 2, // in pixels
25188 barWidth: 1, // in units of the x axis
25189 fill: true,
25190 fillColor: null,
25191 align: "left", // "left", "right", or "center"
25192 horizontal: false,
25193 zero: true
25194 },
25195 shadowSize: 3,
25196 highlightColor: null
25197 },
25198 grid: {
25199 show: true,
25200 aboveData: false,
25201 color: "#545454", // primary color used for outline and labels
25202 backgroundColor: null, // null for transparent, else color
25203 borderColor: null, // set if different from the grid color
25204 tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
25205 margin: 0, // distance from the canvas edge to the grid
25206 labelMargin: 5, // in pixels
25207 axisMargin: 8, // in pixels
25208 borderWidth: 2, // in pixels
25209 minBorderMargin: null, // in pixels, null means taken from points radius
25210 markings: null, // array of ranges or fn: axes -> array of ranges
25211 markingsColor: "#f4f4f4",
25212 markingsLineWidth: 2,
25213 // interactive stuff
25214 clickable: false,
25215 hoverable: false,
25216 autoHighlight: true, // highlight in case mouse is near
25217 mouseActiveRadius: 10 // how far the mouse can be away to activate an item
25218 },
25219 interaction: {
25220 redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow
25221 },
25222 hooks: {}
25223 },
25224 surface = null, // the canvas for the plot itself
25225 overlay = null, // canvas for interactive stuff on top of plot
25226 eventHolder = null, // jQuery object that events should be bound to
25227 ctx = null, octx = null,
25228 xaxes = [], yaxes = [],
25229 plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
25230 plotWidth = 0, plotHeight = 0,
25231 hooks = {
25232 processOptions: [],
25233 processRawData: [],
25234 processDatapoints: [],
25235 processOffset: [],
25236 drawBackground: [],
25237 drawSeries: [],
25238 draw: [],
25239 bindEvents: [],
25240 drawOverlay: [],
25241 shutdown: []
25242 },
25243 plot = this;
25244
25245 // public functions
25246 plot.setData = setData;
25247 plot.setupGrid = setupGrid;
25248 plot.draw = draw;
25249 plot.getPlaceholder = function() { return placeholder; };
25250 plot.getCanvas = function() { return surface.element; };
25251 plot.getPlotOffset = function() { return plotOffset; };
25252 plot.width = function () { return plotWidth; };
25253 plot.height = function () { return plotHeight; };
25254 plot.offset = function () {
25255 var o = eventHolder.offset();
25256 o.left += plotOffset.left;
25257 o.top += plotOffset.top;
25258 return o;
25259 };
25260 plot.getData = function () { return series; };
25261 plot.getAxes = function () {
25262 var res = {}, i;
25263 $.each(xaxes.concat(yaxes), function (_, axis) {
25264 if (axis)
25265 res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;
25266 });
25267 return res;
25268 };
25269 plot.getXAxes = function () { return xaxes; };
25270 plot.getYAxes = function () { return yaxes; };
25271 plot.c2p = canvasToAxisCoords;
25272 plot.p2c = axisToCanvasCoords;
25273 plot.getOptions = function () { return options; };
25274 plot.highlight = highlight;
25275 plot.unhighlight = unhighlight;
25276 plot.triggerRedrawOverlay = triggerRedrawOverlay;
25277 plot.pointOffset = function(point) {
25278 return {
25279 left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10),
25280 top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10)
25281 };
25282 };
25283 plot.shutdown = shutdown;
25284 plot.destroy = function () {
25285 shutdown();
25286 placeholder.removeData("plot").empty();
25287
25288 series = [];
25289 options = null;
25290 surface = null;
25291 overlay = null;
25292 eventHolder = null;
25293 ctx = null;
25294 octx = null;
25295 xaxes = [];
25296 yaxes = [];
25297 hooks = null;
25298 highlights = [];
25299 plot = null;
25300 };
25301 plot.resize = function () {
25302 var width = placeholder.width(),
25303 height = placeholder.height();
25304 surface.resize(width, height);
25305 overlay.resize(width, height);
25306 };
25307
25308 // public attributes
25309 plot.hooks = hooks;
25310
25311 // initialize
25312 initPlugins(plot);
25313 parseOptions(options_);
25314 setupCanvases();
25315 setData(data_);
25316 setupGrid();
25317 draw();
25318 bindEvents();
25319
25320
25321 function executeHooks(hook, args) {
25322 args = [plot].concat(args);
25323 for (var i = 0; i < hook.length; ++i)
25324 hook[i].apply(this, args);
25325 }
25326
25327 function initPlugins() {
25328
25329 // References to key classes, allowing plugins to modify them
25330
25331 var classes = {
25332 Canvas: Canvas
25333 };
25334
25335 for (var i = 0; i < plugins.length; ++i) {
25336 var p = plugins[i];
25337 p.init(plot, classes);
25338 if (p.options)
25339 $.extend(true, options, p.options);
25340 }
25341 }
25342
25343 function parseOptions(opts) {
25344
25345 $.extend(true, options, opts);
25346
25347 // $.extend merges arrays, rather than replacing them. When less
25348 // colors are provided than the size of the default palette, we
25349 // end up with those colors plus the remaining defaults, which is
25350 // not expected behavior; avoid it by replacing them here.
25351
25352 if (opts && opts.colors) {
25353 options.colors = opts.colors;
25354 }
25355
25356 if (options.xaxis.color == null)
25357 options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
25358 if (options.yaxis.color == null)
25359 options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
25360
25361 if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility
25362 options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color;
25363 if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility
25364 options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color;
25365
25366 if (options.grid.borderColor == null)
25367 options.grid.borderColor = options.grid.color;
25368 if (options.grid.tickColor == null)
25369 options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
25370
25371 // Fill in defaults for axis options, including any unspecified
25372 // font-spec fields, if a font-spec was provided.
25373
25374 // If no x/y axis options were provided, create one of each anyway,
25375 // since the rest of the code assumes that they exist.
25376
25377 var i, axisOptions, axisCount,
25378 fontSize = placeholder.css("font-size"),
25379 fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13,
25380 fontDefaults = {
25381 style: placeholder.css("font-style"),
25382 size: Math.round(0.8 * fontSizeDefault),
25383 variant: placeholder.css("font-variant"),
25384 weight: placeholder.css("font-weight"),
25385 family: placeholder.css("font-family")
25386 };
25387
25388 axisCount = options.xaxes.length || 1;
25389 for (i = 0; i < axisCount; ++i) {
25390
25391 axisOptions = options.xaxes[i];
25392 if (axisOptions && !axisOptions.tickColor) {
25393 axisOptions.tickColor = axisOptions.color;
25394 }
25395
25396 axisOptions = $.extend(true, {}, options.xaxis, axisOptions);
25397 options.xaxes[i] = axisOptions;
25398
25399 if (axisOptions.font) {
25400 axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
25401 if (!axisOptions.font.color) {
25402 axisOptions.font.color = axisOptions.color;
25403 }
25404 if (!axisOptions.font.lineHeight) {
25405 axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
25406 }
25407 }
25408 }
25409
25410 axisCount = options.yaxes.length || 1;
25411 for (i = 0; i < axisCount; ++i) {
25412
25413 axisOptions = options.yaxes[i];
25414 if (axisOptions && !axisOptions.tickColor) {
25415 axisOptions.tickColor = axisOptions.color;
25416 }
25417
25418 axisOptions = $.extend(true, {}, options.yaxis, axisOptions);
25419 options.yaxes[i] = axisOptions;
25420
25421 if (axisOptions.font) {
25422 axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
25423 if (!axisOptions.font.color) {
25424 axisOptions.font.color = axisOptions.color;
25425 }
25426 if (!axisOptions.font.lineHeight) {
25427 axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
25428 }
25429 }
25430 }
25431
25432 // backwards compatibility, to be removed in future
25433 if (options.xaxis.noTicks && options.xaxis.ticks == null)
25434 options.xaxis.ticks = options.xaxis.noTicks;
25435 if (options.yaxis.noTicks && options.yaxis.ticks == null)
25436 options.yaxis.ticks = options.yaxis.noTicks;
25437 if (options.x2axis) {
25438 options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
25439 options.xaxes[1].position = "top";
25440 }
25441 if (options.y2axis) {
25442 options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
25443 options.yaxes[1].position = "right";
25444 }
25445 if (options.grid.coloredAreas)
25446 options.grid.markings = options.grid.coloredAreas;
25447 if (options.grid.coloredAreasColor)
25448 options.grid.markingsColor = options.grid.coloredAreasColor;
25449 if (options.lines)
25450 $.extend(true, options.series.lines, options.lines);
25451 if (options.points)
25452 $.extend(true, options.series.points, options.points);
25453 if (options.bars)
25454 $.extend(true, options.series.bars, options.bars);
25455 if (options.shadowSize != null)
25456 options.series.shadowSize = options.shadowSize;
25457 if (options.highlightColor != null)
25458 options.series.highlightColor = options.highlightColor;
25459
25460 // save options on axes for future reference
25461 for (i = 0; i < options.xaxes.length; ++i)
25462 getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];
25463 for (i = 0; i < options.yaxes.length; ++i)
25464 getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];
25465
25466 // add hooks from options
25467 for (var n in hooks)
25468 if (options.hooks[n] && options.hooks[n].length)
25469 hooks[n] = hooks[n].concat(options.hooks[n]);
25470
25471 executeHooks(hooks.processOptions, [options]);
25472 }
25473
25474 function setData(d) {
25475 series = parseData(d);
25476 fillInSeriesOptions();
25477 processData();
25478 }
25479
25480 function parseData(d) {
25481 var res = [];
25482 for (var i = 0; i < d.length; ++i) {
25483 var s = $.extend(true, {}, options.series);
25484
25485 if (d[i].data != null) {
25486 s.data = d[i].data; // move the data instead of deep-copy
25487 delete d[i].data;
25488
25489 $.extend(true, s, d[i]);
25490
25491 d[i].data = s.data;
25492 }
25493 else
25494 s.data = d[i];
25495 res.push(s);
25496 }
25497
25498 return res;
25499 }
25500
25501 function axisNumber(obj, coord) {
25502 var a = obj[coord + "axis"];
25503 if (typeof a == "object") // if we got a real axis, extract number
25504 a = a.n;
25505 if (typeof a != "number")
25506 a = 1; // default to first axis
25507 return a;
25508 }
25509
25510 function allAxes() {
25511 // return flat array without annoying null entries
25512 return $.grep(xaxes.concat(yaxes), function (a) { return a; });
25513 }
25514
25515 function canvasToAxisCoords(pos) {
25516 // return an object with x/y corresponding to all used axes
25517 var res = {}, i, axis;
25518 for (i = 0; i < xaxes.length; ++i) {
25519 axis = xaxes[i];
25520 if (axis && axis.used)
25521 res["x" + axis.n] = axis.c2p(pos.left);
25522 }
25523
25524 for (i = 0; i < yaxes.length; ++i) {
25525 axis = yaxes[i];
25526 if (axis && axis.used)
25527 res["y" + axis.n] = axis.c2p(pos.top);
25528 }
25529
25530 if (res.x1 !== undefined)
25531 res.x = res.x1;
25532 if (res.y1 !== undefined)
25533 res.y = res.y1;
25534
25535 return res;
25536 }
25537
25538 function axisToCanvasCoords(pos) {
25539 // get canvas coords from the first pair of x/y found in pos
25540 var res = {}, i, axis, key;
25541
25542 for (i = 0; i < xaxes.length; ++i) {
25543 axis = xaxes[i];
25544 if (axis && axis.used) {
25545 key = "x" + axis.n;
25546 if (pos[key] == null && axis.n == 1)
25547 key = "x";
25548
25549 if (pos[key] != null) {
25550 res.left = axis.p2c(pos[key]);
25551 break;
25552 }
25553 }
25554 }
25555
25556 for (i = 0; i < yaxes.length; ++i) {
25557 axis = yaxes[i];
25558 if (axis && axis.used) {
25559 key = "y" + axis.n;
25560 if (pos[key] == null && axis.n == 1)
25561 key = "y";
25562
25563 if (pos[key] != null) {
25564 res.top = axis.p2c(pos[key]);
25565 break;
25566 }
25567 }
25568 }
25569
25570 return res;
25571 }
25572
25573 function getOrCreateAxis(axes, number) {
25574 if (!axes[number - 1])
25575 axes[number - 1] = {
25576 n: number, // save the number for future reference
25577 direction: axes == xaxes ? "x" : "y",
25578 options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
25579 };
25580
25581 return axes[number - 1];
25582 }
25583
25584 function fillInSeriesOptions() {
25585
25586 var neededColors = series.length, maxIndex = -1, i;
25587
25588 // Subtract the number of series that already have fixed colors or
25589 // color indexes from the number that we still need to generate.
25590
25591 for (i = 0; i < series.length; ++i) {
25592 var sc = series[i].color;
25593 if (sc != null) {
25594 neededColors--;
25595 if (typeof sc == "number" && sc > maxIndex) {
25596 maxIndex = sc;
25597 }
25598 }
25599 }
25600
25601 // If any of the series have fixed color indexes, then we need to
25602 // generate at least as many colors as the highest index.
25603
25604 if (neededColors <= maxIndex) {
25605 neededColors = maxIndex + 1;
25606 }
25607
25608 // Generate all the colors, using first the option colors and then
25609 // variations on those colors once they're exhausted.
25610
25611 var c, colors = [], colorPool = options.colors,
25612 colorPoolSize = colorPool.length, variation = 0;
25613
25614 for (i = 0; i < neededColors; i++) {
25615
25616 c = $.color.parse(colorPool[i % colorPoolSize] || "#666");
25617
25618 // Each time we exhaust the colors in the pool we adjust
25619 // a scaling factor used to produce more variations on
25620 // those colors. The factor alternates negative/positive
25621 // to produce lighter/darker colors.
25622
25623 // Reset the variation after every few cycles, or else
25624 // it will end up producing only white or black colors.
25625
25626 if (i % colorPoolSize == 0 && i) {
25627 if (variation >= 0) {
25628 if (variation < 0.5) {
25629 variation = -variation - 0.2;
25630 } else variation = 0;
25631 } else variation = -variation;
25632 }
25633
25634 colors[i] = c.scale('rgb', 1 + variation);
25635 }
25636
25637 // Finalize the series options, filling in their colors
25638
25639 var colori = 0, s;
25640 for (i = 0; i < series.length; ++i) {
25641 s = series[i];
25642
25643 // assign colors
25644 if (s.color == null) {
25645 s.color = colors[colori].toString();
25646 ++colori;
25647 }
25648 else if (typeof s.color == "number")
25649 s.color = colors[s.color].toString();
25650
25651 // turn on lines automatically in case nothing is set
25652 if (s.lines.show == null) {
25653 var v, show = true;
25654 for (v in s)
25655 if (s[v] && s[v].show) {
25656 show = false;
25657 break;
25658 }
25659 if (show)
25660 s.lines.show = true;
25661 }
25662
25663 // If nothing was provided for lines.zero, default it to match
25664 // lines.fill, since areas by default should extend to zero.
25665
25666 if (s.lines.zero == null) {
25667 s.lines.zero = !!s.lines.fill;
25668 }
25669
25670 // setup axes
25671 s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
25672 s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
25673 }
25674 }
25675
25676 function processData() {
25677 var topSentry = Number.POSITIVE_INFINITY,
25678 bottomSentry = Number.NEGATIVE_INFINITY,
25679 fakeInfinity = Number.MAX_VALUE,
25680 i, j, k, m, length,
25681 s, points, ps, x, y, axis, val, f, p,
25682 data, format;
25683
25684 function updateAxis(axis, min, max) {
25685 if (min < axis.datamin && min != -fakeInfinity)
25686 axis.datamin = min;
25687 if (max > axis.datamax && max != fakeInfinity)
25688 axis.datamax = max;
25689 }
25690
25691 $.each(allAxes(), function (_, axis) {
25692 // init axis
25693 axis.datamin = topSentry;
25694 axis.datamax = bottomSentry;
25695 axis.used = false;
25696 });
25697
25698 for (i = 0; i < series.length; ++i) {
25699 s = series[i];
25700 s.datapoints = { points: [] };
25701
25702 executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);
25703 }
25704
25705 // first pass: clean and copy data
25706 for (i = 0; i < series.length; ++i) {
25707 s = series[i];
25708
25709 data = s.data;
25710 format = s.datapoints.format;
25711
25712 if (!format) {
25713 format = [];
25714 // find out how to copy
25715 format.push({ x: true, number: true, required: true });
25716 format.push({ y: true, number: true, required: true });
25717
25718 if (s.bars.show || (s.lines.show && s.lines.fill)) {
25719 var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));
25720 format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });
25721 if (s.bars.horizontal) {
25722 delete format[format.length - 1].y;
25723 format[format.length - 1].x = true;
25724 }
25725 }
25726
25727 s.datapoints.format = format;
25728 }
25729
25730 if (s.datapoints.pointsize != null)
25731 continue; // already filled in
25732
25733 s.datapoints.pointsize = format.length;
25734
25735 ps = s.datapoints.pointsize;
25736 points = s.datapoints.points;
25737
25738 var insertSteps = s.lines.show && s.lines.steps;
25739 s.xaxis.used = s.yaxis.used = true;
25740
25741 for (j = k = 0; j < data.length; ++j, k += ps) {
25742 p = data[j];
25743
25744 var nullify = p == null;
25745 if (!nullify) {
25746 for (m = 0; m < ps; ++m) {
25747 val = p[m];
25748 f = format[m];
25749
25750 if (f) {
25751 if (f.number && val != null) {
25752 val = +val; // convert to number
25753 if (isNaN(val))
25754 val = null;
25755 else if (val == Infinity)
25756 val = fakeInfinity;
25757 else if (val == -Infinity)
25758 val = -fakeInfinity;
25759 }
25760
25761 if (val == null) {
25762 if (f.required)
25763 nullify = true;
25764
25765 if (f.defaultValue != null)
25766 val = f.defaultValue;
25767 }
25768 }
25769
25770 points[k + m] = val;
25771 }
25772 }
25773
25774 if (nullify) {
25775 for (m = 0; m < ps; ++m) {
25776 val = points[k + m];
25777 if (val != null) {
25778 f = format[m];
25779 // extract min/max info
25780 if (f.autoscale !== false) {
25781 if (f.x) {
25782 updateAxis(s.xaxis, val, val);
25783 }
25784 if (f.y) {
25785 updateAxis(s.yaxis, val, val);
25786 }
25787 }
25788 }
25789 points[k + m] = null;
25790 }
25791 }
25792 else {
25793 // a little bit of line specific stuff that
25794 // perhaps shouldn't be here, but lacking
25795 // better means...
25796 if (insertSteps && k > 0
25797 && points[k - ps] != null
25798 && points[k - ps] != points[k]
25799 && points[k - ps + 1] != points[k + 1]) {
25800 // copy the point to make room for a middle point
25801 for (m = 0; m < ps; ++m)
25802 points[k + ps + m] = points[k + m];
25803
25804 // middle point has same y
25805 points[k + 1] = points[k - ps + 1];
25806
25807 // we've added a point, better reflect that
25808 k += ps;
25809 }
25810 }
25811 }
25812 }
25813
25814 // give the hooks a chance to run
25815 for (i = 0; i < series.length; ++i) {
25816 s = series[i];
25817
25818 executeHooks(hooks.processDatapoints, [ s, s.datapoints]);
25819 }
25820
25821 // second pass: find datamax/datamin for auto-scaling
25822 for (i = 0; i < series.length; ++i) {
25823 s = series[i];
25824 points = s.datapoints.points;
25825 ps = s.datapoints.pointsize;
25826 format = s.datapoints.format;
25827
25828 var xmin = topSentry, ymin = topSentry,
25829 xmax = bottomSentry, ymax = bottomSentry;
25830
25831 for (j = 0; j < points.length; j += ps) {
25832 if (points[j] == null)
25833 continue;
25834
25835 for (m = 0; m < ps; ++m) {
25836 val = points[j + m];
25837 f = format[m];
25838 if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity)
25839 continue;
25840
25841 if (f.x) {
25842 if (val < xmin)
25843 xmin = val;
25844 if (val > xmax)
25845 xmax = val;
25846 }
25847 if (f.y) {
25848 if (val < ymin)
25849 ymin = val;
25850 if (val > ymax)
25851 ymax = val;
25852 }
25853 }
25854 }
25855
25856 if (s.bars.show) {
25857 // make sure we got room for the bar on the dancing floor
25858 var delta;
25859
25860 switch (s.bars.align) {
25861 case "left":
25862 delta = 0;
25863 break;
25864 case "right":
25865 delta = -s.bars.barWidth;
25866 break;
25867 default:
25868 delta = -s.bars.barWidth / 2;
25869 }
25870
25871 if (s.bars.horizontal) {
25872 ymin += delta;
25873 ymax += delta + s.bars.barWidth;
25874 }
25875 else {
25876 xmin += delta;
25877 xmax += delta + s.bars.barWidth;
25878 }
25879 }
25880
25881 updateAxis(s.xaxis, xmin, xmax);
25882 updateAxis(s.yaxis, ymin, ymax);
25883 }
25884
25885 $.each(allAxes(), function (_, axis) {
25886 if (axis.datamin == topSentry)
25887 axis.datamin = null;
25888 if (axis.datamax == bottomSentry)
25889 axis.datamax = null;
25890 });
25891 }
25892
25893 function setupCanvases() {
25894
25895 // Make sure the placeholder is clear of everything except canvases
25896 // from a previous plot in this container that we'll try to re-use.
25897
25898 placeholder.css("padding", 0) // padding messes up the positioning
25899 .children().filter(function(){
25900 return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base');
25901 }).remove();
25902
25903 if (placeholder.css("position") == 'static')
25904 placeholder.css("position", "relative"); // for positioning labels and overlay
25905
25906 surface = new Canvas("flot-base", placeholder);
25907 overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features
25908
25909 ctx = surface.context;
25910 octx = overlay.context;
25911
25912 // define which element we're listening for events on
25913 eventHolder = $(overlay.element).unbind();
25914
25915 // If we're re-using a plot object, shut down the old one
25916
25917 var existing = placeholder.data("plot");
25918
25919 if (existing) {
25920 existing.shutdown();
25921 overlay.clear();
25922 }
25923
25924 // save in case we get replotted
25925 placeholder.data("plot", plot);
25926 }
25927
25928 function bindEvents() {
25929 // bind events
25930 if (options.grid.hoverable) {
25931 eventHolder.mousemove(onMouseMove);
25932
25933 // Use bind, rather than .mouseleave, because we officially
25934 // still support jQuery 1.2.6, which doesn't define a shortcut
25935 // for mouseenter or mouseleave. This was a bug/oversight that
25936 // was fixed somewhere around 1.3.x. We can return to using
25937 // .mouseleave when we drop support for 1.2.6.
25938
25939 eventHolder.bind("mouseleave", onMouseLeave);
25940 }
25941
25942 if (options.grid.clickable)
25943 eventHolder.click(onClick);
25944
25945 executeHooks(hooks.bindEvents, [eventHolder]);
25946 }
25947
25948 function shutdown() {
25949 if (redrawTimeout)
25950 clearTimeout(redrawTimeout);
25951
25952 eventHolder.unbind("mousemove", onMouseMove);
25953 eventHolder.unbind("mouseleave", onMouseLeave);
25954 eventHolder.unbind("click", onClick);
25955
25956 executeHooks(hooks.shutdown, [eventHolder]);
25957 }
25958
25959 function setTransformationHelpers(axis) {
25960 // set helper functions on the axis, assumes plot area
25961 // has been computed already
25962
25963 function identity(x) { return x; }
25964
25965 var s, m, t = axis.options.transform || identity,
25966 it = axis.options.inverseTransform;
25967
25968 // precompute how much the axis is scaling a point
25969 // in canvas space
25970 if (axis.direction == "x") {
25971 s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));
25972 m = Math.min(t(axis.max), t(axis.min));
25973 }
25974 else {
25975 s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));
25976 s = -s;
25977 m = Math.max(t(axis.max), t(axis.min));
25978 }
25979
25980 // data point to canvas coordinate
25981 if (t == identity) // slight optimization
25982 axis.p2c = function (p) { return (p - m) * s; };
25983 else
25984 axis.p2c = function (p) { return (t(p) - m) * s; };
25985 // canvas coordinate to data point
25986 if (!it)
25987 axis.c2p = function (c) { return m + c / s; };
25988 else
25989 axis.c2p = function (c) { return it(m + c / s); };
25990 }
25991
25992 function measureTickLabels(axis) {
25993
25994 var opts = axis.options,
25995 ticks = axis.ticks || [],
25996 labelWidth = opts.labelWidth || 0,
25997 labelHeight = opts.labelHeight || 0,
25998 maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null),
25999 legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
26000 layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
26001 font = opts.font || "flot-tick-label tickLabel";
26002
26003 for (var i = 0; i < ticks.length; ++i) {
26004
26005 var t = ticks[i];
26006
26007 if (!t.label)
26008 continue;
26009
26010 var info = surface.getTextInfo(layer, t.label, font, null, maxWidth);
26011
26012 labelWidth = Math.max(labelWidth, info.width);
26013 labelHeight = Math.max(labelHeight, info.height);
26014 }
26015
26016 axis.labelWidth = opts.labelWidth || labelWidth;
26017 axis.labelHeight = opts.labelHeight || labelHeight;
26018 }
26019
26020 function allocateAxisBoxFirstPhase(axis) {
26021 // find the bounding box of the axis by looking at label
26022 // widths/heights and ticks, make room by diminishing the
26023 // plotOffset; this first phase only looks at one
26024 // dimension per axis, the other dimension depends on the
26025 // other axes so will have to wait
26026
26027 var lw = axis.labelWidth,
26028 lh = axis.labelHeight,
26029 pos = axis.options.position,
26030 isXAxis = axis.direction === "x",
26031 tickLength = axis.options.tickLength,
26032 axisMargin = options.grid.axisMargin,
26033 padding = options.grid.labelMargin,
26034 innermost = true,
26035 outermost = true,
26036 first = true,
26037 found = false;
26038
26039 // Determine the axis's position in its direction and on its side
26040
26041 $.each(isXAxis ? xaxes : yaxes, function(i, a) {
26042 if (a && a.reserveSpace) {
26043 if (a === axis) {
26044 found = true;
26045 } else if (a.options.position === pos) {
26046 if (found) {
26047 outermost = false;
26048 } else {
26049 innermost = false;
26050 }
26051 }
26052 if (!found) {
26053 first = false;
26054 }
26055 }
26056 });
26057
26058 // The outermost axis on each side has no margin
26059
26060 if (outermost) {
26061 axisMargin = 0;
26062 }
26063
26064 // The ticks for the first axis in each direction stretch across
26065
26066 if (tickLength == null) {
26067 tickLength = first ? "full" : 5;
26068 }
26069
26070 if (!isNaN(+tickLength))
26071 padding += +tickLength;
26072
26073 if (isXAxis) {
26074 lh += padding;
26075
26076 if (pos == "bottom") {
26077 plotOffset.bottom += lh + axisMargin;
26078 axis.box = { top: surface.height - plotOffset.bottom, height: lh };
26079 }
26080 else {
26081 axis.box = { top: plotOffset.top + axisMargin, height: lh };
26082 plotOffset.top += lh + axisMargin;
26083 }
26084 }
26085 else {
26086 lw += padding;
26087
26088 if (pos == "left") {
26089 axis.box = { left: plotOffset.left + axisMargin, width: lw };
26090 plotOffset.left += lw + axisMargin;
26091 }
26092 else {
26093 plotOffset.right += lw + axisMargin;
26094 axis.box = { left: surface.width - plotOffset.right, width: lw };
26095 }
26096 }
26097
26098 // save for future reference
26099 axis.position = pos;
26100 axis.tickLength = tickLength;
26101 axis.box.padding = padding;
26102 axis.innermost = innermost;
26103 }
26104
26105 function allocateAxisBoxSecondPhase(axis) {
26106 // now that all axis boxes have been placed in one
26107 // dimension, we can set the remaining dimension coordinates
26108 if (axis.direction == "x") {
26109 axis.box.left = plotOffset.left - axis.labelWidth / 2;
26110 axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth;
26111 }
26112 else {
26113 axis.box.top = plotOffset.top - axis.labelHeight / 2;
26114 axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight;
26115 }
26116 }
26117
26118 function adjustLayoutForThingsStickingOut() {
26119 // possibly adjust plot offset to ensure everything stays
26120 // inside the canvas and isn't clipped off
26121
26122 var minMargin = options.grid.minBorderMargin,
26123 axis, i;
26124
26125 // check stuff from the plot (FIXME: this should just read
26126 // a value from the series, otherwise it's impossible to
26127 // customize)
26128 if (minMargin == null) {
26129 minMargin = 0;
26130 for (i = 0; i < series.length; ++i)
26131 minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2));
26132 }
26133
26134 var margins = {
26135 left: minMargin,
26136 right: minMargin,
26137 top: minMargin,
26138 bottom: minMargin
26139 };
26140
26141 // check axis labels, note we don't check the actual
26142 // labels but instead use the overall width/height to not
26143 // jump as much around with replots
26144 $.each(allAxes(), function (_, axis) {
26145 if (axis.reserveSpace && axis.ticks && axis.ticks.length) {
26146 var lastTick = axis.ticks[axis.ticks.length - 1];
26147 if (axis.direction === "x") {
26148 margins.left = Math.max(margins.left, axis.labelWidth / 2);
26149 if (lastTick.v <= axis.max) {
26150 margins.right = Math.max(margins.right, axis.labelWidth / 2);
26151 }
26152 } else {
26153 margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2);
26154 if (lastTick.v <= axis.max) {
26155 margins.top = Math.max(margins.top, axis.labelHeight / 2);
26156 }
26157 }
26158 }
26159 });
26160
26161 plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left));
26162 plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right));
26163 plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top));
26164 plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom));
26165 }
26166
26167 function setupGrid() {
26168 var i, axes = allAxes(), showGrid = options.grid.show;
26169
26170 // Initialize the plot's offset from the edge of the canvas
26171
26172 for (var a in plotOffset) {
26173 var margin = options.grid.margin || 0;
26174 plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0;
26175 }
26176
26177 executeHooks(hooks.processOffset, [plotOffset]);
26178
26179 // If the grid is visible, add its border width to the offset
26180
26181 for (var a in plotOffset) {
26182 if(typeof(options.grid.borderWidth) == "object") {
26183 plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0;
26184 }
26185 else {
26186 plotOffset[a] += showGrid ? options.grid.borderWidth : 0;
26187 }
26188 }
26189
26190 // init axes
26191 $.each(axes, function (_, axis) {
26192 axis.show = axis.options.show;
26193 if (axis.show == null)
26194 axis.show = axis.used; // by default an axis is visible if it's got data
26195
26196 axis.reserveSpace = axis.show || axis.options.reserveSpace;
26197
26198 setRange(axis);
26199 });
26200
26201 if (showGrid) {
26202
26203 var allocatedAxes = $.grep(axes, function (axis) { return axis.reserveSpace; });
26204
26205 $.each(allocatedAxes, function (_, axis) {
26206 // make the ticks
26207 setupTickGeneration(axis);
26208 setTicks(axis);
26209 snapRangeToTicks(axis, axis.ticks);
26210 // find labelWidth/Height for axis
26211 measureTickLabels(axis);
26212 });
26213
26214 // with all dimensions calculated, we can compute the
26215 // axis bounding boxes, start from the outside
26216 // (reverse order)
26217 for (i = allocatedAxes.length - 1; i >= 0; --i)
26218 allocateAxisBoxFirstPhase(allocatedAxes[i]);
26219
26220 // make sure we've got enough space for things that
26221 // might stick out
26222 adjustLayoutForThingsStickingOut();
26223
26224 $.each(allocatedAxes, function (_, axis) {
26225 allocateAxisBoxSecondPhase(axis);
26226 });
26227 }
26228
26229 plotWidth = surface.width - plotOffset.left - plotOffset.right;
26230 plotHeight = surface.height - plotOffset.bottom - plotOffset.top;
26231
26232 // now we got the proper plot dimensions, we can compute the scaling
26233 $.each(axes, function (_, axis) {
26234 setTransformationHelpers(axis);
26235 });
26236
26237 if (showGrid) {
26238 drawAxisLabels();
26239 }
26240
26241 insertLegend();
26242 }
26243
26244 function setRange(axis) {
26245 var opts = axis.options,
26246 min = +(opts.min != null ? opts.min : axis.datamin),
26247 max = +(opts.max != null ? opts.max : axis.datamax),
26248 delta = max - min;
26249
26250 if (delta == 0.0) {
26251 // degenerate case
26252 var widen = max == 0 ? 1 : 0.01;
26253
26254 if (opts.min == null)
26255 min -= widen;
26256 // always widen max if we couldn't widen min to ensure we
26257 // don't fall into min == max which doesn't work
26258 if (opts.max == null || opts.min != null)
26259 max += widen;
26260 }
26261 else {
26262 // consider autoscaling
26263 var margin = opts.autoscaleMargin;
26264 if (margin != null) {
26265 if (opts.min == null) {
26266 min -= delta * margin;
26267 // make sure we don't go below zero if all values
26268 // are positive
26269 if (min < 0 && axis.datamin != null && axis.datamin >= 0)
26270 min = 0;
26271 }
26272 if (opts.max == null) {
26273 max += delta * margin;
26274 if (max > 0 && axis.datamax != null && axis.datamax <= 0)
26275 max = 0;
26276 }
26277 }
26278 }
26279 axis.min = min;
26280 axis.max = max;
26281 }
26282
26283 function setupTickGeneration(axis) {
26284 var opts = axis.options;
26285
26286 // estimate number of ticks
26287 var noTicks;
26288 if (typeof opts.ticks == "number" && opts.ticks > 0)
26289 noTicks = opts.ticks;
26290 else
26291 // heuristic based on the model a*sqrt(x) fitted to
26292 // some data points that seemed reasonable
26293 noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height);
26294
26295 var delta = (axis.max - axis.min) / noTicks,
26296 dec = -Math.floor(Math.log(delta) / Math.LN10),
26297 maxDec = opts.tickDecimals;
26298
26299 if (maxDec != null && dec > maxDec) {
26300 dec = maxDec;
26301 }
26302
26303 var magn = Math.pow(10, -dec),
26304 norm = delta / magn, // norm is between 1.0 and 10.0
26305 size;
26306
26307 if (norm < 1.5) {
26308 size = 1;
26309 } else if (norm < 3) {
26310 size = 2;
26311 // special case for 2.5, requires an extra decimal
26312 if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
26313 size = 2.5;
26314 ++dec;
26315 }
26316 } else if (norm < 7.5) {
26317 size = 5;
26318 } else {
26319 size = 10;
26320 }
26321
26322 size *= magn;
26323
26324 if (opts.minTickSize != null && size < opts.minTickSize) {
26325 size = opts.minTickSize;
26326 }
26327
26328 axis.delta = delta;
26329 axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
26330 axis.tickSize = opts.tickSize || size;
26331
26332 // Time mode was moved to a plug-in in 0.8, but since so many people use this
26333 // we'll add an especially friendly make sure they remembered to include it.
26334
26335 if (opts.mode == "time" && !axis.tickGenerator) {
26336 throw new Error("Time mode requires the flot.time plugin.");
26337 }
26338
26339 // Flot supports base-10 axes; any other mode else is handled by a plug-in,
26340 // like flot.time.js.
26341
26342 if (!axis.tickGenerator) {
26343
26344 axis.tickGenerator = function (axis) {
26345
26346 var ticks = [],
26347 start = floorInBase(axis.min, axis.tickSize),
26348 i = 0,
26349 v = Number.NaN,
26350 prev;
26351
26352 do {
26353 prev = v;
26354 v = start + i * axis.tickSize;
26355 ticks.push(v);
26356 ++i;
26357 } while (v < axis.max && v != prev);
26358 return ticks;
26359 };
26360
26361 axis.tickFormatter = function (value, axis) {
26362
26363 var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;
26364 var formatted = "" + Math.round(value * factor) / factor;
26365
26366 // If tickDecimals was specified, ensure that we have exactly that
26367 // much precision; otherwise default to the value's own precision.
26368
26369 if (axis.tickDecimals != null) {
26370 var decimal = formatted.indexOf(".");
26371 var precision = decimal == -1 ? 0 : formatted.length - decimal - 1;
26372 if (precision < axis.tickDecimals) {
26373 return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision);
26374 }
26375 }
26376
26377 return formatted;
26378 };
26379 }
26380
26381 if ($.isFunction(opts.tickFormatter))
26382 axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
26383
26384 if (opts.alignTicksWithAxis != null) {
26385 var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
26386 if (otherAxis && otherAxis.used && otherAxis != axis) {
26387 // consider snapping min/max to outermost nice ticks
26388 var niceTicks = axis.tickGenerator(axis);
26389 if (niceTicks.length > 0) {
26390 if (opts.min == null)
26391 axis.min = Math.min(axis.min, niceTicks[0]);
26392 if (opts.max == null && niceTicks.length > 1)
26393 axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
26394 }
26395
26396 axis.tickGenerator = function (axis) {
26397 // copy ticks, scaled to this axis
26398 var ticks = [], v, i;
26399 for (i = 0; i < otherAxis.ticks.length; ++i) {
26400 v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);
26401 v = axis.min + v * (axis.max - axis.min);
26402 ticks.push(v);
26403 }
26404 return ticks;
26405 };
26406
26407 // we might need an extra decimal since forced
26408 // ticks don't necessarily fit naturally
26409 if (!axis.mode && opts.tickDecimals == null) {
26410 var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
26411 ts = axis.tickGenerator(axis);
26412
26413 // only proceed if the tick interval rounded
26414 // with an extra decimal doesn't give us a
26415 // zero at end
26416 if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))
26417 axis.tickDecimals = extraDec;
26418 }
26419 }
26420 }
26421 }
26422
26423 function setTicks(axis) {
26424 var oticks = axis.options.ticks, ticks = [];
26425 if (oticks == null || (typeof oticks == "number" && oticks > 0))
26426 ticks = axis.tickGenerator(axis);
26427 else if (oticks) {
26428 if ($.isFunction(oticks))
26429 // generate the ticks
26430 ticks = oticks(axis);
26431 else
26432 ticks = oticks;
26433 }
26434
26435 // clean up/labelify the supplied ticks, copy them over
26436 var i, v;
26437 axis.ticks = [];
26438 for (i = 0; i < ticks.length; ++i) {
26439 var label = null;
26440 var t = ticks[i];
26441 if (typeof t == "object") {
26442 v = +t[0];
26443 if (t.length > 1)
26444 label = t[1];
26445 }
26446 else
26447 v = +t;
26448 if (label == null)
26449 label = axis.tickFormatter(v, axis);
26450 if (!isNaN(v))
26451 axis.ticks.push({ v: v, label: label });
26452 }
26453 }
26454
26455 function snapRangeToTicks(axis, ticks) {
26456 if (axis.options.autoscaleMargin && ticks.length > 0) {
26457 // snap to ticks
26458 if (axis.options.min == null)
26459 axis.min = Math.min(axis.min, ticks[0].v);
26460 if (axis.options.max == null && ticks.length > 1)
26461 axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
26462 }
26463 }
26464
26465 function draw() {
26466
26467 surface.clear();
26468
26469 executeHooks(hooks.drawBackground, [ctx]);
26470
26471 var grid = options.grid;
26472
26473 // draw background, if any
26474 if (grid.show && grid.backgroundColor)
26475 drawBackground();
26476
26477 if (grid.show && !grid.aboveData) {
26478 drawGrid();
26479 }
26480
26481 for (var i = 0; i < series.length; ++i) {
26482 executeHooks(hooks.drawSeries, [ctx, series[i]]);
26483 drawSeries(series[i]);
26484 }
26485
26486 executeHooks(hooks.draw, [ctx]);
26487
26488 if (grid.show && grid.aboveData) {
26489 drawGrid();
26490 }
26491
26492 surface.render();
26493
26494 // A draw implies that either the axes or data have changed, so we
26495 // should probably update the overlay highlights as well.
26496
26497 triggerRedrawOverlay();
26498 }
26499
26500 function extractRange(ranges, coord) {
26501 var axis, from, to, key, axes = allAxes();
26502
26503 for (var i = 0; i < axes.length; ++i) {
26504 axis = axes[i];
26505 if (axis.direction == coord) {
26506 key = coord + axis.n + "axis";
26507 if (!ranges[key] && axis.n == 1)
26508 key = coord + "axis"; // support x1axis as xaxis
26509 if (ranges[key]) {
26510 from = ranges[key].from;
26511 to = ranges[key].to;
26512 break;
26513 }
26514 }
26515 }
26516
26517 // backwards-compat stuff - to be removed in future
26518 if (!ranges[key]) {
26519 axis = coord == "x" ? xaxes[0] : yaxes[0];
26520 from = ranges[coord + "1"];
26521 to = ranges[coord + "2"];
26522 }
26523
26524 // auto-reverse as an added bonus
26525 if (from != null && to != null && from > to) {
26526 var tmp = from;
26527 from = to;
26528 to = tmp;
26529 }
26530
26531 return { from: from, to: to, axis: axis };
26532 }
26533
26534 function drawBackground() {
26535 ctx.save();
26536 ctx.translate(plotOffset.left, plotOffset.top);
26537
26538 ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
26539 ctx.fillRect(0, 0, plotWidth, plotHeight);
26540 ctx.restore();
26541 }
26542
26543 function drawGrid() {
26544 var i, axes, bw, bc;
26545
26546 ctx.save();
26547 ctx.translate(plotOffset.left, plotOffset.top);
26548
26549 // draw markings
26550 var markings = options.grid.markings;
26551 if (markings) {
26552 if ($.isFunction(markings)) {
26553 axes = plot.getAxes();
26554 // xmin etc. is backwards compatibility, to be
26555 // removed in the future
26556 axes.xmin = axes.xaxis.min;
26557 axes.xmax = axes.xaxis.max;
26558 axes.ymin = axes.yaxis.min;
26559 axes.ymax = axes.yaxis.max;
26560
26561 markings = markings(axes);
26562 }
26563
26564 for (i = 0; i < markings.length; ++i) {
26565 var m = markings[i],
26566 xrange = extractRange(m, "x"),
26567 yrange = extractRange(m, "y");
26568
26569 // fill in missing
26570 if (xrange.from == null)
26571 xrange.from = xrange.axis.min;
26572 if (xrange.to == null)
26573 xrange.to = xrange.axis.max;
26574 if (yrange.from == null)
26575 yrange.from = yrange.axis.min;
26576 if (yrange.to == null)
26577 yrange.to = yrange.axis.max;
26578
26579 // clip
26580 if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
26581 yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)
26582 continue;
26583
26584 xrange.from = Math.max(xrange.from, xrange.axis.min);
26585 xrange.to = Math.min(xrange.to, xrange.axis.max);
26586 yrange.from = Math.max(yrange.from, yrange.axis.min);
26587 yrange.to = Math.min(yrange.to, yrange.axis.max);
26588
26589 if (xrange.from == xrange.to && yrange.from == yrange.to)
26590 continue;
26591
26592 // then draw
26593 xrange.from = xrange.axis.p2c(xrange.from);
26594 xrange.to = xrange.axis.p2c(xrange.to);
26595 yrange.from = yrange.axis.p2c(yrange.from);
26596 yrange.to = yrange.axis.p2c(yrange.to);
26597
26598 if (xrange.from == xrange.to || yrange.from == yrange.to) {
26599 // draw line
26600 ctx.beginPath();
26601 ctx.strokeStyle = m.color || options.grid.markingsColor;
26602 ctx.lineWidth = m.lineWidth || options.grid.markingsLineWidth;
26603 ctx.moveTo(xrange.from, yrange.from);
26604 ctx.lineTo(xrange.to, yrange.to);
26605 ctx.stroke();
26606 }
26607 else {
26608 // fill area
26609 ctx.fillStyle = m.color || options.grid.markingsColor;
26610 ctx.fillRect(xrange.from, yrange.to,
26611 xrange.to - xrange.from,
26612 yrange.from - yrange.to);
26613 }
26614 }
26615 }
26616
26617 // draw the ticks
26618 axes = allAxes();
26619 bw = options.grid.borderWidth;
26620
26621 for (var j = 0; j < axes.length; ++j) {
26622 var axis = axes[j], box = axis.box,
26623 t = axis.tickLength, x, y, xoff, yoff;
26624 if (!axis.show || axis.ticks.length == 0)
26625 continue;
26626
26627 ctx.lineWidth = 1;
26628
26629 // find the edges
26630 if (axis.direction == "x") {
26631 x = 0;
26632 if (t == "full")
26633 y = (axis.position == "top" ? 0 : plotHeight);
26634 else
26635 y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);
26636 }
26637 else {
26638 y = 0;
26639 if (t == "full")
26640 x = (axis.position == "left" ? 0 : plotWidth);
26641 else
26642 x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
26643 }
26644
26645 // draw tick bar
26646 if (!axis.innermost) {
26647 ctx.strokeStyle = axis.options.color;
26648 ctx.beginPath();
26649 xoff = yoff = 0;
26650 if (axis.direction == "x")
26651 xoff = plotWidth + 1;
26652 else
26653 yoff = plotHeight + 1;
26654
26655 if (ctx.lineWidth == 1) {
26656 if (axis.direction == "x") {
26657 y = Math.floor(y) + 0.5;
26658 } else {
26659 x = Math.floor(x) + 0.5;
26660 }
26661 }
26662
26663 ctx.moveTo(x, y);
26664 ctx.lineTo(x + xoff, y + yoff);
26665 ctx.stroke();
26666 }
26667
26668 // draw ticks
26669
26670 ctx.strokeStyle = axis.options.tickColor;
26671
26672 ctx.beginPath();
26673 for (i = 0; i < axis.ticks.length; ++i) {
26674 var v = axis.ticks[i].v;
26675
26676 xoff = yoff = 0;
26677
26678 if (isNaN(v) || v < axis.min || v > axis.max
26679 // skip those lying on the axes if we got a border
26680 || (t == "full"
26681 && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0)
26682 && (v == axis.min || v == axis.max)))
26683 continue;
26684
26685 if (axis.direction == "x") {
26686 x = axis.p2c(v);
26687 yoff = t == "full" ? -plotHeight : t;
26688
26689 if (axis.position == "top")
26690 yoff = -yoff;
26691 }
26692 else {
26693 y = axis.p2c(v);
26694 xoff = t == "full" ? -plotWidth : t;
26695
26696 if (axis.position == "left")
26697 xoff = -xoff;
26698 }
26699
26700 if (ctx.lineWidth == 1) {
26701 if (axis.direction == "x")
26702 x = Math.floor(x) + 0.5;
26703 else
26704 y = Math.floor(y) + 0.5;
26705 }
26706
26707 ctx.moveTo(x, y);
26708 ctx.lineTo(x + xoff, y + yoff);
26709 }
26710
26711 ctx.stroke();
26712 }
26713
26714
26715 // draw border
26716 if (bw) {
26717 // If either borderWidth or borderColor is an object, then draw the border
26718 // line by line instead of as one rectangle
26719 bc = options.grid.borderColor;
26720 if(typeof bw == "object" || typeof bc == "object") {
26721 if (typeof bw !== "object") {
26722 bw = {top: bw, right: bw, bottom: bw, left: bw};
26723 }
26724 if (typeof bc !== "object") {
26725 bc = {top: bc, right: bc, bottom: bc, left: bc};
26726 }
26727
26728 if (bw.top > 0) {
26729 ctx.strokeStyle = bc.top;
26730 ctx.lineWidth = bw.top;
26731 ctx.beginPath();
26732 ctx.moveTo(0 - bw.left, 0 - bw.top/2);
26733 ctx.lineTo(plotWidth, 0 - bw.top/2);
26734 ctx.stroke();
26735 }
26736
26737 if (bw.right > 0) {
26738 ctx.strokeStyle = bc.right;
26739 ctx.lineWidth = bw.right;
26740 ctx.beginPath();
26741 ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top);
26742 ctx.lineTo(plotWidth + bw.right / 2, plotHeight);
26743 ctx.stroke();
26744 }
26745
26746 if (bw.bottom > 0) {
26747 ctx.strokeStyle = bc.bottom;
26748 ctx.lineWidth = bw.bottom;
26749 ctx.beginPath();
26750 ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2);
26751 ctx.lineTo(0, plotHeight + bw.bottom / 2);
26752 ctx.stroke();
26753 }
26754
26755 if (bw.left > 0) {
26756 ctx.strokeStyle = bc.left;
26757 ctx.lineWidth = bw.left;
26758 ctx.beginPath();
26759 ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom);
26760 ctx.lineTo(0- bw.left/2, 0);
26761 ctx.stroke();
26762 }
26763 }
26764 else {
26765 ctx.lineWidth = bw;
26766 ctx.strokeStyle = options.grid.borderColor;
26767 ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
26768 }
26769 }
26770
26771 ctx.restore();
26772 }
26773
26774 function drawAxisLabels() {
26775
26776 $.each(allAxes(), function (_, axis) {
26777 var box = axis.box,
26778 legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
26779 layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
26780 font = axis.options.font || "flot-tick-label tickLabel",
26781 tick, x, y, halign, valign;
26782
26783 // Remove text before checking for axis.show and ticks.length;
26784 // otherwise plugins, like flot-tickrotor, that draw their own
26785 // tick labels will end up with both theirs and the defaults.
26786
26787 surface.removeText(layer);
26788
26789 if (!axis.show || axis.ticks.length == 0)
26790 return;
26791
26792 for (var i = 0; i < axis.ticks.length; ++i) {
26793
26794 tick = axis.ticks[i];
26795 if (!tick.label || tick.v < axis.min || tick.v > axis.max)
26796 continue;
26797
26798 if (axis.direction == "x") {
26799 halign = "center";
26800 x = plotOffset.left + axis.p2c(tick.v);
26801 if (axis.position == "bottom") {
26802 y = box.top + box.padding;
26803 } else {
26804 y = box.top + box.height - box.padding;
26805 valign = "bottom";
26806 }
26807 } else {
26808 valign = "middle";
26809 y = plotOffset.top + axis.p2c(tick.v);
26810 if (axis.position == "left") {
26811 x = box.left + box.width - box.padding;
26812 halign = "right";
26813 } else {
26814 x = box.left + box.padding;
26815 }
26816 }
26817
26818 surface.addText(layer, x, y, tick.label, font, null, null, halign, valign);
26819 }
26820 });
26821 }
26822
26823 function drawSeries(series) {
26824 if (series.lines.show)
26825 drawSeriesLines(series);
26826 if (series.bars.show)
26827 drawSeriesBars(series);
26828 if (series.points.show)
26829 drawSeriesPoints(series);
26830 }
26831
26832 function drawSeriesLines(series) {
26833 function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
26834 var points = datapoints.points,
26835 ps = datapoints.pointsize,
26836 prevx = null, prevy = null;
26837
26838 ctx.beginPath();
26839 for (var i = ps; i < points.length; i += ps) {
26840 var x1 = points[i - ps], y1 = points[i - ps + 1],
26841 x2 = points[i], y2 = points[i + 1];
26842
26843 if (x1 == null || x2 == null)
26844 continue;
26845
26846 // clip with ymin
26847 if (y1 <= y2 && y1 < axisy.min) {
26848 if (y2 < axisy.min)
26849 continue; // line segment is outside
26850 // compute new intersection point
26851 x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
26852 y1 = axisy.min;
26853 }
26854 else if (y2 <= y1 && y2 < axisy.min) {
26855 if (y1 < axisy.min)
26856 continue;
26857 x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
26858 y2 = axisy.min;
26859 }
26860
26861 // clip with ymax
26862 if (y1 >= y2 && y1 > axisy.max) {
26863 if (y2 > axisy.max)
26864 continue;
26865 x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
26866 y1 = axisy.max;
26867 }
26868 else if (y2 >= y1 && y2 > axisy.max) {
26869 if (y1 > axisy.max)
26870 continue;
26871 x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
26872 y2 = axisy.max;
26873 }
26874
26875 // clip with xmin
26876 if (x1 <= x2 && x1 < axisx.min) {
26877 if (x2 < axisx.min)
26878 continue;
26879 y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
26880 x1 = axisx.min;
26881 }
26882 else if (x2 <= x1 && x2 < axisx.min) {
26883 if (x1 < axisx.min)
26884 continue;
26885 y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
26886 x2 = axisx.min;
26887 }
26888
26889 // clip with xmax
26890 if (x1 >= x2 && x1 > axisx.max) {
26891 if (x2 > axisx.max)
26892 continue;
26893 y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
26894 x1 = axisx.max;
26895 }
26896 else if (x2 >= x1 && x2 > axisx.max) {
26897 if (x1 > axisx.max)
26898 continue;
26899 y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
26900 x2 = axisx.max;
26901 }
26902
26903 if (x1 != prevx || y1 != prevy)
26904 ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
26905
26906 prevx = x2;
26907 prevy = y2;
26908 ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
26909 }
26910 ctx.stroke();
26911 }
26912
26913 function plotLineArea(datapoints, axisx, axisy) {
26914 var points = datapoints.points,
26915 ps = datapoints.pointsize,
26916 bottom = Math.min(Math.max(0, axisy.min), axisy.max),
26917 i = 0, top, areaOpen = false,
26918 ypos = 1, segmentStart = 0, segmentEnd = 0;
26919
26920 // we process each segment in two turns, first forward
26921 // direction to sketch out top, then once we hit the
26922 // end we go backwards to sketch the bottom
26923 while (true) {
26924 if (ps > 0 && i > points.length + ps)
26925 break;
26926
26927 i += ps; // ps is negative if going backwards
26928
26929 var x1 = points[i - ps],
26930 y1 = points[i - ps + ypos],
26931 x2 = points[i], y2 = points[i + ypos];
26932
26933 if (areaOpen) {
26934 if (ps > 0 && x1 != null && x2 == null) {
26935 // at turning point
26936 segmentEnd = i;
26937 ps = -ps;
26938 ypos = 2;
26939 continue;
26940 }
26941
26942 if (ps < 0 && i == segmentStart + ps) {
26943 // done with the reverse sweep
26944 ctx.fill();
26945 areaOpen = false;
26946 ps = -ps;
26947 ypos = 1;
26948 i = segmentStart = segmentEnd + ps;
26949 continue;
26950 }
26951 }
26952
26953 if (x1 == null || x2 == null)
26954 continue;
26955
26956 // clip x values
26957
26958 // clip with xmin
26959 if (x1 <= x2 && x1 < axisx.min) {
26960 if (x2 < axisx.min)
26961 continue;
26962 y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
26963 x1 = axisx.min;
26964 }
26965 else if (x2 <= x1 && x2 < axisx.min) {
26966 if (x1 < axisx.min)
26967 continue;
26968 y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
26969 x2 = axisx.min;
26970 }
26971
26972 // clip with xmax
26973 if (x1 >= x2 && x1 > axisx.max) {
26974 if (x2 > axisx.max)
26975 continue;
26976 y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
26977 x1 = axisx.max;
26978 }
26979 else if (x2 >= x1 && x2 > axisx.max) {
26980 if (x1 > axisx.max)
26981 continue;
26982 y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
26983 x2 = axisx.max;
26984 }
26985
26986 if (!areaOpen) {
26987 // open area
26988 ctx.beginPath();
26989 ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
26990 areaOpen = true;
26991 }
26992
26993 // now first check the case where both is outside
26994 if (y1 >= axisy.max && y2 >= axisy.max) {
26995 ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
26996 ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
26997 continue;
26998 }
26999 else if (y1 <= axisy.min && y2 <= axisy.min) {
27000 ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
27001 ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
27002 continue;
27003 }
27004
27005 // else it's a bit more complicated, there might
27006 // be a flat maxed out rectangle first, then a
27007 // triangular cutout or reverse; to find these
27008 // keep track of the current x values
27009 var x1old = x1, x2old = x2;
27010
27011 // clip the y values, without shortcutting, we
27012 // go through all cases in turn
27013
27014 // clip with ymin
27015 if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
27016 x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
27017 y1 = axisy.min;
27018 }
27019 else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
27020 x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
27021 y2 = axisy.min;
27022 }
27023
27024 // clip with ymax
27025 if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
27026 x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
27027 y1 = axisy.max;
27028 }
27029 else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
27030 x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
27031 y2 = axisy.max;
27032 }
27033
27034 // if the x value was changed we got a rectangle
27035 // to fill
27036 if (x1 != x1old) {
27037 ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
27038 // it goes to (x1, y1), but we fill that below
27039 }
27040
27041 // fill triangular section, this sometimes result
27042 // in redundant points if (x1, y1) hasn't changed
27043 // from previous line to, but we just ignore that
27044 ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
27045 ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
27046
27047 // fill the other rectangle if it's there
27048 if (x2 != x2old) {
27049 ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
27050 ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
27051 }
27052 }
27053 }
27054
27055 ctx.save();
27056 ctx.translate(plotOffset.left, plotOffset.top);
27057 ctx.lineJoin = "round";
27058
27059 var lw = series.lines.lineWidth,
27060 sw = series.shadowSize;
27061 // FIXME: consider another form of shadow when filling is turned on
27062 if (lw > 0 && sw > 0) {
27063 // draw shadow as a thick and thin line with transparency
27064 ctx.lineWidth = sw;
27065 ctx.strokeStyle = "rgba(0,0,0,0.1)";
27066 // position shadow at angle from the mid of line
27067 var angle = Math.PI/18;
27068 plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);
27069 ctx.lineWidth = sw/2;
27070 plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);
27071 }
27072
27073 ctx.lineWidth = lw;
27074 ctx.strokeStyle = series.color;
27075 var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);
27076 if (fillStyle) {
27077 ctx.fillStyle = fillStyle;
27078 plotLineArea(series.datapoints, series.xaxis, series.yaxis);
27079 }
27080
27081 if (lw > 0)
27082 plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);
27083 ctx.restore();
27084 }
27085
27086 function drawSeriesPoints(series) {
27087 function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {
27088 var points = datapoints.points, ps = datapoints.pointsize;
27089
27090 for (var i = 0; i < points.length; i += ps) {
27091 var x = points[i], y = points[i + 1];
27092 if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
27093 continue;
27094
27095 ctx.beginPath();
27096 x = axisx.p2c(x);
27097 y = axisy.p2c(y) + offset;
27098 if (symbol == "circle")
27099 ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
27100 else
27101 symbol(ctx, x, y, radius, shadow);
27102 ctx.closePath();
27103
27104 if (fillStyle) {
27105 ctx.fillStyle = fillStyle;
27106 ctx.fill();
27107 }
27108 ctx.stroke();
27109 }
27110 }
27111
27112 ctx.save();
27113 ctx.translate(plotOffset.left, plotOffset.top);
27114
27115 var lw = series.points.lineWidth,
27116 sw = series.shadowSize,
27117 radius = series.points.radius,
27118 symbol = series.points.symbol;
27119
27120 // If the user sets the line width to 0, we change it to a very
27121 // small value. A line width of 0 seems to force the default of 1.
27122 // Doing the conditional here allows the shadow setting to still be
27123 // optional even with a lineWidth of 0.
27124
27125 if( lw == 0 )
27126 lw = 0.0001;
27127
27128 if (lw > 0 && sw > 0) {
27129 // draw shadow in two steps
27130 var w = sw / 2;
27131 ctx.lineWidth = w;
27132 ctx.strokeStyle = "rgba(0,0,0,0.1)";
27133 plotPoints(series.datapoints, radius, null, w + w/2, true,
27134 series.xaxis, series.yaxis, symbol);
27135
27136 ctx.strokeStyle = "rgba(0,0,0,0.2)";
27137 plotPoints(series.datapoints, radius, null, w/2, true,
27138 series.xaxis, series.yaxis, symbol);
27139 }
27140
27141 ctx.lineWidth = lw;
27142 ctx.strokeStyle = series.color;
27143 plotPoints(series.datapoints, radius,
27144 getFillStyle(series.points, series.color), 0, false,
27145 series.xaxis, series.yaxis, symbol);
27146 ctx.restore();
27147 }
27148
27149 function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
27150 var left, right, bottom, top,
27151 drawLeft, drawRight, drawTop, drawBottom,
27152 tmp;
27153
27154 // in horizontal mode, we start the bar from the left
27155 // instead of from the bottom so it appears to be
27156 // horizontal rather than vertical
27157 if (horizontal) {
27158 drawBottom = drawRight = drawTop = true;
27159 drawLeft = false;
27160 left = b;
27161 right = x;
27162 top = y + barLeft;
27163 bottom = y + barRight;
27164
27165 // account for negative bars
27166 if (right < left) {
27167 tmp = right;
27168 right = left;
27169 left = tmp;
27170 drawLeft = true;
27171 drawRight = false;
27172 }
27173 }
27174 else {
27175 drawLeft = drawRight = drawTop = true;
27176 drawBottom = false;
27177 left = x + barLeft;
27178 right = x + barRight;
27179 bottom = b;
27180 top = y;
27181
27182 // account for negative bars
27183 if (top < bottom) {
27184 tmp = top;
27185 top = bottom;
27186 bottom = tmp;
27187 drawBottom = true;
27188 drawTop = false;
27189 }
27190 }
27191
27192 // clip
27193 if (right < axisx.min || left > axisx.max ||
27194 top < axisy.min || bottom > axisy.max)
27195 return;
27196
27197 if (left < axisx.min) {
27198 left = axisx.min;
27199 drawLeft = false;
27200 }
27201
27202 if (right > axisx.max) {
27203 right = axisx.max;
27204 drawRight = false;
27205 }
27206
27207 if (bottom < axisy.min) {
27208 bottom = axisy.min;
27209 drawBottom = false;
27210 }
27211
27212 if (top > axisy.max) {
27213 top = axisy.max;
27214 drawTop = false;
27215 }
27216
27217 left = axisx.p2c(left);
27218 bottom = axisy.p2c(bottom);
27219 right = axisx.p2c(right);
27220 top = axisy.p2c(top);
27221
27222 // fill the bar
27223 if (fillStyleCallback) {
27224 c.fillStyle = fillStyleCallback(bottom, top);
27225 c.fillRect(left, top, right - left, bottom - top)
27226 }
27227
27228 // draw outline
27229 if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
27230 c.beginPath();
27231
27232 // FIXME: inline moveTo is buggy with excanvas
27233 c.moveTo(left, bottom);
27234 if (drawLeft)
27235 c.lineTo(left, top);
27236 else
27237 c.moveTo(left, top);
27238 if (drawTop)
27239 c.lineTo(right, top);
27240 else
27241 c.moveTo(right, top);
27242 if (drawRight)
27243 c.lineTo(right, bottom);
27244 else
27245 c.moveTo(right, bottom);
27246 if (drawBottom)
27247 c.lineTo(left, bottom);
27248 else
27249 c.moveTo(left, bottom);
27250 c.stroke();
27251 }
27252 }
27253
27254 function drawSeriesBars(series) {
27255 function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
27256 var points = datapoints.points, ps = datapoints.pointsize;
27257
27258 for (var i = 0; i < points.length; i += ps) {
27259 if (points[i] == null)
27260 continue;
27261 drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
27262 }
27263 }
27264
27265 ctx.save();
27266 ctx.translate(plotOffset.left, plotOffset.top);
27267
27268 // FIXME: figure out a way to add shadows (for instance along the right edge)
27269 ctx.lineWidth = series.bars.lineWidth;
27270 ctx.strokeStyle = series.color;
27271
27272 var barLeft;
27273
27274 switch (series.bars.align) {
27275 case "left":
27276 barLeft = 0;
27277 break;
27278 case "right":
27279 barLeft = -series.bars.barWidth;
27280 break;
27281 default:
27282 barLeft = -series.bars.barWidth / 2;
27283 }
27284
27285 var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
27286 plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);
27287 ctx.restore();
27288 }
27289
27290 function getFillStyle(filloptions, seriesColor, bottom, top) {
27291 var fill = filloptions.fill;
27292 if (!fill)
27293 return null;
27294
27295 if (filloptions.fillColor)
27296 return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
27297
27298 var c = $.color.parse(seriesColor);
27299 c.a = typeof fill == "number" ? fill : 0.4;
27300 c.normalize();
27301 return c.toString();
27302 }
27303
27304 function insertLegend() {
27305
27306 if (options.legend.container != null) {
27307 $(options.legend.container).html("");
27308 } else {
27309 placeholder.find(".legend").remove();
27310 }
27311
27312 if (!options.legend.show) {
27313 return;
27314 }
27315
27316 var fragments = [], entries = [], rowStarted = false,
27317 lf = options.legend.labelFormatter, s, label;
27318
27319 // Build a list of legend entries, with each having a label and a color
27320
27321 for (var i = 0; i < series.length; ++i) {
27322 s = series[i];
27323 if (s.label) {
27324 label = lf ? lf(s.label, s) : s.label;
27325 if (label) {
27326 entries.push({
27327 label: label,
27328 color: s.color
27329 });
27330 }
27331 }
27332 }
27333
27334 // Sort the legend using either the default or a custom comparator
27335
27336 if (options.legend.sorted) {
27337 if ($.isFunction(options.legend.sorted)) {
27338 entries.sort(options.legend.sorted);
27339 } else if (options.legend.sorted == "reverse") {
27340 entries.reverse();
27341 } else {
27342 var ascending = options.legend.sorted != "descending";
27343 entries.sort(function(a, b) {
27344 return a.label == b.label ? 0 : (
27345 (a.label < b.label) != ascending ? 1 : -1 // Logical XOR
27346 );
27347 });
27348 }
27349 }
27350
27351 // Generate markup for the list of entries, in their final order
27352
27353 for (var i = 0; i < entries.length; ++i) {
27354
27355 var entry = entries[i];
27356
27357 if (i % options.legend.noColumns == 0) {
27358 if (rowStarted)
27359 fragments.push('</tr>');
27360 fragments.push('<tr>');
27361 rowStarted = true;
27362 }
27363
27364 fragments.push(
27365 '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden"></div></div></td>' +
27366 '<td class="legendLabel">' + entry.label + '</td>'
27367 );
27368 }
27369
27370 if (rowStarted)
27371 fragments.push('</tr>');
27372
27373 if (fragments.length == 0)
27374 return;
27375
27376 var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
27377 if (options.legend.container != null)
27378 $(options.legend.container).html(table);
27379 else {
27380 var pos = "",
27381 p = options.legend.position,
27382 m = options.legend.margin;
27383 if (m[0] == null)
27384 m = [m, m];
27385 if (p.charAt(0) == "n")
27386 pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
27387 else if (p.charAt(0) == "s")
27388 pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
27389 if (p.charAt(1) == "e")
27390 pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
27391 else if (p.charAt(1) == "w")
27392 pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
27393 var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder);
27394 if (options.legend.backgroundOpacity != 0.0) {
27395 // put in the transparent background
27396 // separately to avoid blended labels and
27397 // label boxes
27398 var c = options.legend.backgroundColor;
27399 if (c == null) {
27400 c = options.grid.backgroundColor;
27401 if (c && typeof c == "string")
27402 c = $.color.parse(c);
27403 else
27404 c = $.color.extract(legend, 'background-color');
27405 c.a = 1;
27406 c = c.toString();
27407 }
27408 var div = legend.children();
27409 $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);
27410 }
27411 }
27412 }
27413
27414
27415 // interactive features
27416
27417 var highlights = [],
27418 redrawTimeout = null;
27419
27420 // returns the data item the mouse is over, or null if none is found
27421 function findNearbyItem(mouseX, mouseY, seriesFilter) {
27422 var maxDistance = options.grid.mouseActiveRadius,
27423 smallestDistance = maxDistance * maxDistance + 1,
27424 item = null, foundPoint = false, i, j, ps;
27425
27426 for (i = series.length - 1; i >= 0; --i) {
27427 if (!seriesFilter(series[i]))
27428 continue;
27429
27430 var s = series[i],
27431 axisx = s.xaxis,
27432 axisy = s.yaxis,
27433 points = s.datapoints.points,
27434 mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
27435 my = axisy.c2p(mouseY),
27436 maxx = maxDistance / axisx.scale,
27437 maxy = maxDistance / axisy.scale;
27438
27439 ps = s.datapoints.pointsize;
27440 // with inverse transforms, we can't use the maxx/maxy
27441 // optimization, sadly
27442 if (axisx.options.inverseTransform)
27443 maxx = Number.MAX_VALUE;
27444 if (axisy.options.inverseTransform)
27445 maxy = Number.MAX_VALUE;
27446
27447 if (s.lines.show || s.points.show) {
27448 for (j = 0; j < points.length; j += ps) {
27449 var x = points[j], y = points[j + 1];
27450 if (x == null)
27451 continue;
27452
27453 // For points and lines, the cursor must be within a
27454 // certain distance to the data point
27455 if (x - mx > maxx || x - mx < -maxx ||
27456 y - my > maxy || y - my < -maxy)
27457 continue;
27458
27459 // We have to calculate distances in pixels, not in
27460 // data units, because the scales of the axes may be different
27461 var dx = Math.abs(axisx.p2c(x) - mouseX),
27462 dy = Math.abs(axisy.p2c(y) - mouseY),
27463 dist = dx * dx + dy * dy; // we save the sqrt
27464
27465 // use <= to ensure last point takes precedence
27466 // (last generally means on top of)
27467 if (dist < smallestDistance) {
27468 smallestDistance = dist;
27469 item = [i, j / ps];
27470 }
27471 }
27472 }
27473
27474 if (s.bars.show && !item) { // no other point can be nearby
27475
27476 var barLeft, barRight;
27477
27478 switch (s.bars.align) {
27479 case "left":
27480 barLeft = 0;
27481 break;
27482 case "right":
27483 barLeft = -s.bars.barWidth;
27484 break;
27485 default:
27486 barLeft = -s.bars.barWidth / 2;
27487 }
27488
27489 barRight = barLeft + s.bars.barWidth;
27490
27491 for (j = 0; j < points.length; j += ps) {
27492 var x = points[j], y = points[j + 1], b = points[j + 2];
27493 if (x == null)
27494 continue;
27495
27496 // for a bar graph, the cursor must be inside the bar
27497 if (series[i].bars.horizontal ?
27498 (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
27499 my >= y + barLeft && my <= y + barRight) :
27500 (mx >= x + barLeft && mx <= x + barRight &&
27501 my >= Math.min(b, y) && my <= Math.max(b, y)))
27502 item = [i, j / ps];
27503 }
27504 }
27505 }
27506
27507 if (item) {
27508 i = item[0];
27509 j = item[1];
27510 ps = series[i].datapoints.pointsize;
27511
27512 return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
27513 dataIndex: j,
27514 series: series[i],
27515 seriesIndex: i };
27516 }
27517
27518 return null;
27519 }
27520
27521 function onMouseMove(e) {
27522 if (options.grid.hoverable)
27523 triggerClickHoverEvent("plothover", e,
27524 function (s) { return s["hoverable"] != false; });
27525 }
27526
27527 function onMouseLeave(e) {
27528 if (options.grid.hoverable)
27529 triggerClickHoverEvent("plothover", e,
27530 function (s) { return false; });
27531 }
27532
27533 function onClick(e) {
27534 triggerClickHoverEvent("plotclick", e,
27535 function (s) { return s["clickable"] != false; });
27536 }
27537
27538 // trigger click or hover event (they send the same parameters
27539 // so we share their code)
27540 function triggerClickHoverEvent(eventname, event, seriesFilter) {
27541 var offset = eventHolder.offset(),
27542 canvasX = event.pageX - offset.left - plotOffset.left,
27543 canvasY = event.pageY - offset.top - plotOffset.top,
27544 pos = canvasToAxisCoords({ left: canvasX, top: canvasY });
27545
27546 pos.pageX = event.pageX;
27547 pos.pageY = event.pageY;
27548
27549 var item = findNearbyItem(canvasX, canvasY, seriesFilter);
27550
27551 if (item) {
27552 // fill in mouse pos for any listeners out there
27553 item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10);
27554 item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10);
27555 }
27556
27557 if (options.grid.autoHighlight) {
27558 // clear auto-highlights
27559 for (var i = 0; i < highlights.length; ++i) {
27560 var h = highlights[i];
27561 if (h.auto == eventname &&
27562 !(item && h.series == item.series &&
27563 h.point[0] == item.datapoint[0] &&
27564 h.point[1] == item.datapoint[1]))
27565 unhighlight(h.series, h.point);
27566 }
27567
27568 if (item)
27569 highlight(item.series, item.datapoint, eventname);
27570 }
27571
27572 placeholder.trigger(eventname, [ pos, item ]);
27573 }
27574
27575 function triggerRedrawOverlay() {
27576 var t = options.interaction.redrawOverlayInterval;
27577 if (t == -1) { // skip event queue
27578 drawOverlay();
27579 return;
27580 }
27581
27582 if (!redrawTimeout)
27583 redrawTimeout = setTimeout(drawOverlay, t);
27584 }
27585
27586 function drawOverlay() {
27587 redrawTimeout = null;
27588
27589 // draw highlights
27590 octx.save();
27591 overlay.clear();
27592 octx.translate(plotOffset.left, plotOffset.top);
27593
27594 var i, hi;
27595 for (i = 0; i < highlights.length; ++i) {
27596 hi = highlights[i];
27597
27598 if (hi.series.bars.show)
27599 drawBarHighlight(hi.series, hi.point);
27600 else
27601 drawPointHighlight(hi.series, hi.point);
27602 }
27603 octx.restore();
27604
27605 executeHooks(hooks.drawOverlay, [octx]);
27606 }
27607
27608 function highlight(s, point, auto) {
27609 if (typeof s == "number")
27610 s = series[s];
27611
27612 if (typeof point == "number") {
27613 var ps = s.datapoints.pointsize;
27614 point = s.datapoints.points.slice(ps * point, ps * (point + 1));
27615 }
27616
27617 var i = indexOfHighlight(s, point);
27618 if (i == -1) {
27619 highlights.push({ series: s, point: point, auto: auto });
27620
27621 triggerRedrawOverlay();
27622 }
27623 else if (!auto)
27624 highlights[i].auto = false;
27625 }
27626
27627 function unhighlight(s, point) {
27628 if (s == null && point == null) {
27629 highlights = [];
27630 triggerRedrawOverlay();
27631 return;
27632 }
27633
27634 if (typeof s == "number")
27635 s = series[s];
27636
27637 if (typeof point == "number") {
27638 var ps = s.datapoints.pointsize;
27639 point = s.datapoints.points.slice(ps * point, ps * (point + 1));
27640 }
27641
27642 var i = indexOfHighlight(s, point);
27643 if (i != -1) {
27644 highlights.splice(i, 1);
27645
27646 triggerRedrawOverlay();
27647 }
27648 }
27649
27650 function indexOfHighlight(s, p) {
27651 for (var i = 0; i < highlights.length; ++i) {
27652 var h = highlights[i];
27653 if (h.series == s && h.point[0] == p[0]
27654 && h.point[1] == p[1])
27655 return i;
27656 }
27657 return -1;
27658 }
27659
27660 function drawPointHighlight(series, point) {
27661 var x = point[0], y = point[1],
27662 axisx = series.xaxis, axisy = series.yaxis,
27663 highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();
27664
27665 if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
27666 return;
27667
27668 var pointRadius = series.points.radius + series.points.lineWidth / 2;
27669 octx.lineWidth = pointRadius;
27670 octx.strokeStyle = highlightColor;
27671 var radius = 1.5 * pointRadius;
27672 x = axisx.p2c(x);
27673 y = axisy.p2c(y);
27674
27675 octx.beginPath();
27676 if (series.points.symbol == "circle")
27677 octx.arc(x, y, radius, 0, 2 * Math.PI, false);
27678 else
27679 series.points.symbol(octx, x, y, radius, false);
27680 octx.closePath();
27681 octx.stroke();
27682 }
27683
27684 function drawBarHighlight(series, point) {
27685 var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
27686 fillStyle = highlightColor,
27687 barLeft;
27688
27689 switch (series.bars.align) {
27690 case "left":
27691 barLeft = 0;
27692 break;
27693 case "right":
27694 barLeft = -series.bars.barWidth;
27695 break;
27696 default:
27697 barLeft = -series.bars.barWidth / 2;
27698 }
27699
27700 octx.lineWidth = series.bars.lineWidth;
27701 octx.strokeStyle = highlightColor;
27702
27703 drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
27704 function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
27705 }
27706
27707 function getColorOrGradient(spec, bottom, top, defaultColor) {
27708 if (typeof spec == "string")
27709 return spec;
27710 else {
27711 // assume this is a gradient spec; IE currently only
27712 // supports a simple vertical gradient properly, so that's
27713 // what we support too
27714 var gradient = ctx.createLinearGradient(0, top, 0, bottom);
27715
27716 for (var i = 0, l = spec.colors.length; i < l; ++i) {
27717 var c = spec.colors[i];
27718 if (typeof c != "string") {
27719 var co = $.color.parse(defaultColor);
27720 if (c.brightness != null)
27721 co = co.scale('rgb', c.brightness);
27722 if (c.opacity != null)
27723 co.a *= c.opacity;
27724 c = co.toString();
27725 }
27726 gradient.addColorStop(i / (l - 1), c);
27727 }
27728
27729 return gradient;
27730 }
27731 }
27732 }
27733
27734 // Add the plot function to the top level of the jQuery object
27735
27736 $.plot = function(placeholder, data, options) {
27737 //var t0 = new Date();
27738 var plot = new Plot($(placeholder), data, options, $.plot.plugins);
27739 //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));
27740 return plot;
27741 };
27742
27743 $.plot.version = "0.8.2";
27744
27745 $.plot.plugins = [];
27746
27747 // Also add the plot function as a chainable property
27748
27749 $.fn.plot = function(data, options) {
27750 return this.each(function() {
27751 $.plot(this, data, options);
27752 });
27753 };
27754
27755 // round to nearby lower multiple of base
27756 function floorInBase(n, base) {
27757 return base * Math.floor(n / base);
27758 }
27759
27760 })(jQuery);
27761 /* Flot plugin for rendering pie charts.
27762
27763 Copyright (c) 2007-2013 IOLA and Ole Laursen.
27764 Licensed under the MIT license.
27765
27766 The plugin assumes that each series has a single data value, and that each
27767 value is a positive integer or zero. Negative numbers don't make sense for a
27768 pie chart, and have unpredictable results. The values do NOT need to be
27769 passed in as percentages; the plugin will calculate the total and per-slice
27770 percentages internally.
27771
27772 * Created by Brian Medendorp
27773
27774 * Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars
27775
27776 The plugin supports these options:
27777
27778 series: {
27779 pie: {
27780 show: true/false
27781 radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto'
27782 innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect
27783 startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result
27784 tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show)
27785 offset: {
27786 top: integer value to move the pie up or down
27787 left: integer value to move the pie left or right, or 'auto'
27788 },
27789 stroke: {
27790 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF')
27791 width: integer pixel width of the stroke
27792 },
27793 label: {
27794 show: true/false, or 'auto'
27795 formatter: a user-defined function that modifies the text/style of the label text
27796 radius: 0-1 for percentage of fullsize, or a specified pixel length
27797 background: {
27798 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000')
27799 opacity: 0-1
27800 },
27801 threshold: 0-1 for the percentage value at which to hide labels (if they're too small)
27802 },
27803 combine: {
27804 threshold: 0-1 for the percentage value at which to combine slices (if they're too small)
27805 color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined
27806 label: any text value of what the combined slice should be labeled
27807 }
27808 highlight: {
27809 opacity: 0-1
27810 }
27811 }
27812 }
27813
27814 More detail and specific examples can be found in the included HTML file.
27815
27816 */
27817
27818 (function($) {
27819
27820 // Maximum redraw attempts when fitting labels within the plot
27821
27822 var REDRAW_ATTEMPTS = 10;
27823
27824 // Factor by which to shrink the pie when fitting labels within the plot
27825
27826 var REDRAW_SHRINK = 0.95;
27827
27828 function init(plot) {
27829
27830 var canvas = null,
27831 target = null,
27832 options = null,
27833 maxRadius = null,
27834 centerLeft = null,
27835 centerTop = null,
27836 processed = false,
27837 ctx = null;
27838
27839 // interactive variables
27840
27841 var highlights = [];
27842
27843 // add hook to determine if pie plugin in enabled, and then perform necessary operations
27844
27845 plot.hooks.processOptions.push(function(plot, options) {
27846 if (options.series.pie.show) {
27847
27848 options.grid.show = false;
27849
27850 // set labels.show
27851
27852 if (options.series.pie.label.show == "auto") {
27853 if (options.legend.show) {
27854 options.series.pie.label.show = false;
27855 } else {
27856 options.series.pie.label.show = true;
27857 }
27858 }
27859
27860 // set radius
27861
27862 if (options.series.pie.radius == "auto") {
27863 if (options.series.pie.label.show) {
27864 options.series.pie.radius = 3/4;
27865 } else {
27866 options.series.pie.radius = 1;
27867 }
27868 }
27869
27870 // ensure sane tilt
27871
27872 if (options.series.pie.tilt > 1) {
27873 options.series.pie.tilt = 1;
27874 } else if (options.series.pie.tilt < 0) {
27875 options.series.pie.tilt = 0;
27876 }
27877 }
27878 });
27879
27880 plot.hooks.bindEvents.push(function(plot, eventHolder) {
27881 var options = plot.getOptions();
27882 if (options.series.pie.show) {
27883 if (options.grid.hoverable) {
27884 eventHolder.unbind("mousemove").mousemove(onMouseMove);
27885 }
27886 if (options.grid.clickable) {
27887 eventHolder.unbind("click").click(onClick);
27888 }
27889 }
27890 });
27891
27892 plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) {
27893 var options = plot.getOptions();
27894 if (options.series.pie.show) {
27895 processDatapoints(plot, series, data, datapoints);
27896 }
27897 });
27898
27899 plot.hooks.drawOverlay.push(function(plot, octx) {
27900 var options = plot.getOptions();
27901 if (options.series.pie.show) {
27902 drawOverlay(plot, octx);
27903 }
27904 });
27905
27906 plot.hooks.draw.push(function(plot, newCtx) {
27907 var options = plot.getOptions();
27908 if (options.series.pie.show) {
27909 draw(plot, newCtx);
27910 }
27911 });
27912
27913 function processDatapoints(plot, series, datapoints) {
27914 if (!processed) {
27915 processed = true;
27916 canvas = plot.getCanvas();
27917 target = $(canvas).parent();
27918 options = plot.getOptions();
27919 plot.setData(combine(plot.getData()));
27920 }
27921 }
27922
27923 function combine(data) {
27924
27925 var total = 0,
27926 combined = 0,
27927 numCombined = 0,
27928 color = options.series.pie.combine.color,
27929 newdata = [];
27930
27931 // Fix up the raw data from Flot, ensuring the data is numeric
27932
27933 for (var i = 0; i < data.length; ++i) {
27934
27935 var value = data[i].data;
27936
27937 // If the data is an array, we'll assume that it's a standard
27938 // Flot x-y pair, and are concerned only with the second value.
27939
27940 // Note how we use the original array, rather than creating a
27941 // new one; this is more efficient and preserves any extra data
27942 // that the user may have stored in higher indexes.
27943
27944 if ($.isArray(value) && value.length == 1) {
27945 value = value[0];
27946 }
27947
27948 if ($.isArray(value)) {
27949 // Equivalent to $.isNumeric() but compatible with jQuery < 1.7
27950 if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) {
27951 value[1] = +value[1];
27952 } else {
27953 value[1] = 0;
27954 }
27955 } else if (!isNaN(parseFloat(value)) && isFinite(value)) {
27956 value = [1, +value];
27957 } else {
27958 value = [1, 0];
27959 }
27960
27961 data[i].data = [value];
27962 }
27963
27964 // Sum up all the slices, so we can calculate percentages for each
27965
27966 for (var i = 0; i < data.length; ++i) {
27967 total += data[i].data[0][1];
27968 }
27969
27970 // Count the number of slices with percentages below the combine
27971 // threshold; if it turns out to be just one, we won't combine.
27972
27973 for (var i = 0; i < data.length; ++i) {
27974 var value = data[i].data[0][1];
27975 if (value / total <= options.series.pie.combine.threshold) {
27976 combined += value;
27977 numCombined++;
27978 if (!color) {
27979 color = data[i].color;
27980 }
27981 }
27982 }
27983
27984 for (var i = 0; i < data.length; ++i) {
27985 var value = data[i].data[0][1];
27986 if (numCombined < 2 || value / total > options.series.pie.combine.threshold) {
27987 newdata.push({
27988 data: [[1, value]],
27989 color: data[i].color,
27990 label: data[i].label,
27991 angle: value * Math.PI * 2 / total,
27992 percent: value / (total / 100)
27993 });
27994 }
27995 }
27996
27997 if (numCombined > 1) {
27998 newdata.push({
27999 data: [[1, combined]],
28000 color: color,
28001 label: options.series.pie.combine.label,
28002 angle: combined * Math.PI * 2 / total,
28003 percent: combined / (total / 100)
28004 });
28005 }
28006
28007 return newdata;
28008 }
28009
28010 function draw(plot, newCtx) {
28011
28012 if (!target) {
28013 return; // if no series were passed
28014 }
28015
28016 var canvasWidth = plot.getPlaceholder().width(),
28017 canvasHeight = plot.getPlaceholder().height(),
28018 legendWidth = target.children().filter(".legend").children().width() || 0;
28019
28020 ctx = newCtx;
28021
28022 // WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE!
28023
28024 // When combining smaller slices into an 'other' slice, we need to
28025 // add a new series. Since Flot gives plugins no way to modify the
28026 // list of series, the pie plugin uses a hack where the first call
28027 // to processDatapoints results in a call to setData with the new
28028 // list of series, then subsequent processDatapoints do nothing.
28029
28030 // The plugin-global 'processed' flag is used to control this hack;
28031 // it starts out false, and is set to true after the first call to
28032 // processDatapoints.
28033
28034 // Unfortunately this turns future setData calls into no-ops; they
28035 // call processDatapoints, the flag is true, and nothing happens.
28036
28037 // To fix this we'll set the flag back to false here in draw, when
28038 // all series have been processed, so the next sequence of calls to
28039 // processDatapoints once again starts out with a slice-combine.
28040 // This is really a hack; in 0.9 we need to give plugins a proper
28041 // way to modify series before any processing begins.
28042
28043 processed = false;
28044
28045 // calculate maximum radius and center point
28046
28047 maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
28048 centerTop = canvasHeight / 2 + options.series.pie.offset.top;
28049 centerLeft = canvasWidth / 2;
28050
28051 if (options.series.pie.offset.left == "auto") {
28052 if (options.legend.position.match("w")) {
28053 centerLeft += legendWidth / 2;
28054 } else {
28055 centerLeft -= legendWidth / 2;
28056 }
28057 if (centerLeft < maxRadius) {
28058 centerLeft = maxRadius;
28059 } else if (centerLeft > canvasWidth - maxRadius) {
28060 centerLeft = canvasWidth - maxRadius;
28061 }
28062 } else {
28063 centerLeft += options.series.pie.offset.left;
28064 }
28065
28066 var slices = plot.getData(),
28067 attempts = 0;
28068
28069 // Keep shrinking the pie's radius until drawPie returns true,
28070 // indicating that all the labels fit, or we try too many times.
28071
28072 do {
28073 if (attempts > 0) {
28074 maxRadius *= REDRAW_SHRINK;
28075 }
28076 attempts += 1;
28077 clear();
28078 if (options.series.pie.tilt <= 0.8) {
28079 drawShadow();
28080 }
28081 } while (!drawPie() && attempts < REDRAW_ATTEMPTS)
28082
28083 if (attempts >= REDRAW_ATTEMPTS) {
28084 clear();
28085 target.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>");
28086 }
28087
28088 if (plot.setSeries && plot.insertLegend) {
28089 plot.setSeries(slices);
28090 plot.insertLegend();
28091 }
28092
28093 // we're actually done at this point, just defining internal functions at this point
28094
28095 function clear() {
28096 ctx.clearRect(0, 0, canvasWidth, canvasHeight);
28097 target.children().filter(".pieLabel, .pieLabelBackground").remove();
28098 }
28099
28100 function drawShadow() {
28101
28102 var shadowLeft = options.series.pie.shadow.left;
28103 var shadowTop = options.series.pie.shadow.top;
28104 var edge = 10;
28105 var alpha = options.series.pie.shadow.alpha;
28106 var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
28107
28108 if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) {
28109 return; // shadow would be outside canvas, so don't draw it
28110 }
28111
28112 ctx.save();
28113 ctx.translate(shadowLeft,shadowTop);
28114 ctx.globalAlpha = alpha;
28115 ctx.fillStyle = "#000";
28116
28117 // center and rotate to starting position
28118
28119 ctx.translate(centerLeft,centerTop);
28120 ctx.scale(1, options.series.pie.tilt);
28121
28122 //radius -= edge;
28123
28124 for (var i = 1; i <= edge; i++) {
28125 ctx.beginPath();
28126 ctx.arc(0, 0, radius, 0, Math.PI * 2, false);
28127 ctx.fill();
28128 radius -= i;
28129 }
28130
28131 ctx.restore();
28132 }
28133
28134 function drawPie() {
28135
28136 var startAngle = Math.PI * options.series.pie.startAngle;
28137 var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
28138
28139 // center and rotate to starting position
28140
28141 ctx.save();
28142 ctx.translate(centerLeft,centerTop);
28143 ctx.scale(1, options.series.pie.tilt);
28144 //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
28145
28146 // draw slices
28147
28148 ctx.save();
28149 var currentAngle = startAngle;
28150 for (var i = 0; i < slices.length; ++i) {
28151 slices[i].startAngle = currentAngle;
28152 drawSlice(slices[i].angle, slices[i].color, true);
28153 }
28154 ctx.restore();
28155
28156 // draw slice outlines
28157
28158 if (options.series.pie.stroke.width > 0) {
28159 ctx.save();
28160 ctx.lineWidth = options.series.pie.stroke.width;
28161 currentAngle = startAngle;
28162 for (var i = 0; i < slices.length; ++i) {
28163 drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
28164 }
28165 ctx.restore();
28166 }
28167
28168 // draw donut hole
28169
28170 drawDonutHole(ctx);
28171
28172 ctx.restore();
28173
28174 // Draw the labels, returning true if they fit within the plot
28175
28176 if (options.series.pie.label.show) {
28177 return drawLabels();
28178 } else return true;
28179
28180 function drawSlice(angle, color, fill) {
28181
28182 if (angle <= 0 || isNaN(angle)) {
28183 return;
28184 }
28185
28186 if (fill) {
28187 ctx.fillStyle = color;
28188 } else {
28189 ctx.strokeStyle = color;
28190 ctx.lineJoin = "round";
28191 }
28192
28193 ctx.beginPath();
28194 if (Math.abs(angle - Math.PI * 2) > 0.000000001) {
28195 ctx.moveTo(0, 0); // Center of the pie
28196 }
28197
28198 //ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera
28199 ctx.arc(0, 0, radius,currentAngle, currentAngle + angle / 2, false);
28200 ctx.arc(0, 0, radius,currentAngle + angle / 2, currentAngle + angle, false);
28201 ctx.closePath();
28202 //ctx.rotate(angle); // This doesn't work properly in Opera
28203 currentAngle += angle;
28204
28205 if (fill) {
28206 ctx.fill();
28207 } else {
28208 ctx.stroke();
28209 }
28210 }
28211
28212 function drawLabels() {
28213
28214 var currentAngle = startAngle;
28215 var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius;
28216
28217 for (var i = 0; i < slices.length; ++i) {
28218 if (slices[i].percent >= options.series.pie.label.threshold * 100) {
28219 if (!drawLabel(slices[i], currentAngle, i)) {
28220 return false;
28221 }
28222 }
28223 currentAngle += slices[i].angle;
28224 }
28225
28226 return true;
28227
28228 function drawLabel(slice, startAngle, index) {
28229
28230 if (slice.data[0][1] == 0) {
28231 return true;
28232 }
28233
28234 // format label text
28235
28236 var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
28237
28238 if (lf) {
28239 text = lf(slice.label, slice);
28240 } else {
28241 text = slice.label;
28242 }
28243
28244 if (plf) {
28245 text = plf(text, slice);
28246 }
28247
28248 var halfAngle = ((startAngle + slice.angle) + startAngle) / 2;
28249 var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
28250 var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
28251
28252 var html = "<span class='pieLabel' id='pieLabel" + index + "' style='position:absolute;top:" + y + "px;left:" + x + "px;'>" + text + "</span>";
28253 target.append(html);
28254
28255 var label = target.children("#pieLabel" + index);
28256 var labelTop = (y - label.height() / 2);
28257 var labelLeft = (x - label.width() / 2);
28258
28259 label.css("top", labelTop);
28260 label.css("left", labelLeft);
28261
28262 // check to make sure that the label is not outside the canvas
28263
28264 if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) {
28265 return false;
28266 }
28267
28268 if (options.series.pie.label.background.opacity != 0) {
28269
28270 // put in the transparent background separately to avoid blended labels and label boxes
28271
28272 var c = options.series.pie.label.background.color;
28273
28274 if (c == null) {
28275 c = slice.color;
28276 }
28277
28278 var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;";
28279 $("<div class='pieLabelBackground' style='position:absolute;width:" + label.width() + "px;height:" + label.height() + "px;" + pos + "background-color:" + c + ";'></div>")
28280 .css("opacity", options.series.pie.label.background.opacity)
28281 .insertBefore(label);
28282 }
28283
28284 return true;
28285 } // end individual label function
28286 } // end drawLabels function
28287 } // end drawPie function
28288 } // end draw function
28289
28290 // Placed here because it needs to be accessed from multiple locations
28291
28292 function drawDonutHole(layer) {
28293 if (options.series.pie.innerRadius > 0) {
28294
28295 // subtract the center
28296
28297 layer.save();
28298 var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
28299 layer.globalCompositeOperation = "destination-out"; // this does not work with excanvas, but it will fall back to using the stroke color
28300 layer.beginPath();
28301 layer.fillStyle = options.series.pie.stroke.color;
28302 layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
28303 layer.fill();
28304 layer.closePath();
28305 layer.restore();
28306
28307 // add inner stroke
28308
28309 layer.save();
28310 layer.beginPath();
28311 layer.strokeStyle = options.series.pie.stroke.color;
28312 layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
28313 layer.stroke();
28314 layer.closePath();
28315 layer.restore();
28316
28317 // TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
28318 }
28319 }
28320
28321 //-- Additional Interactive related functions --
28322
28323 function isPointInPoly(poly, pt) {
28324 for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
28325 ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
28326 && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
28327 && (c = !c);
28328 return c;
28329 }
28330
28331 function findNearbySlice(mouseX, mouseY) {
28332
28333 var slices = plot.getData(),
28334 options = plot.getOptions(),
28335 radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius,
28336 x, y;
28337
28338 for (var i = 0; i < slices.length; ++i) {
28339
28340 var s = slices[i];
28341
28342 if (s.pie.show) {
28343
28344 ctx.save();
28345 ctx.beginPath();
28346 ctx.moveTo(0, 0); // Center of the pie
28347 //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
28348 ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false);
28349 ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false);
28350 ctx.closePath();
28351 x = mouseX - centerLeft;
28352 y = mouseY - centerTop;
28353
28354 if (ctx.isPointInPath) {
28355 if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) {
28356 ctx.restore();
28357 return {
28358 datapoint: [s.percent, s.data],
28359 dataIndex: 0,
28360 series: s,
28361 seriesIndex: i
28362 };
28363 }
28364 } else {
28365
28366 // excanvas for IE doesn;t support isPointInPath, this is a workaround.
28367
28368 var p1X = radius * Math.cos(s.startAngle),
28369 p1Y = radius * Math.sin(s.startAngle),
28370 p2X = radius * Math.cos(s.startAngle + s.angle / 4),
28371 p2Y = radius * Math.sin(s.startAngle + s.angle / 4),
28372 p3X = radius * Math.cos(s.startAngle + s.angle / 2),
28373 p3Y = radius * Math.sin(s.startAngle + s.angle / 2),
28374 p4X = radius * Math.cos(s.startAngle + s.angle / 1.5),
28375 p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5),
28376 p5X = radius * Math.cos(s.startAngle + s.angle),
28377 p5Y = radius * Math.sin(s.startAngle + s.angle),
28378 arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]],
28379 arrPoint = [x, y];
28380
28381 // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
28382
28383 if (isPointInPoly(arrPoly, arrPoint)) {
28384 ctx.restore();
28385 return {
28386 datapoint: [s.percent, s.data],
28387 dataIndex: 0,
28388 series: s,
28389 seriesIndex: i
28390 };
28391 }
28392 }
28393
28394 ctx.restore();
28395 }
28396 }
28397
28398 return null;
28399 }
28400
28401 function onMouseMove(e) {
28402 triggerClickHoverEvent("plothover", e);
28403 }
28404
28405 function onClick(e) {
28406 triggerClickHoverEvent("plotclick", e);
28407 }
28408
28409 // trigger click or hover event (they send the same parameters so we share their code)
28410
28411 function triggerClickHoverEvent(eventname, e) {
28412
28413 var offset = plot.offset();
28414 var canvasX = parseInt(e.pageX - offset.left);
28415 var canvasY = parseInt(e.pageY - offset.top);
28416 var item = findNearbySlice(canvasX, canvasY);
28417
28418 if (options.grid.autoHighlight) {
28419
28420 // clear auto-highlights
28421
28422 for (var i = 0; i < highlights.length; ++i) {
28423 var h = highlights[i];
28424 if (h.auto == eventname && !(item && h.series == item.series)) {
28425 unhighlight(h.series);
28426 }
28427 }
28428 }
28429
28430 // highlight the slice
28431
28432 if (item) {
28433 highlight(item.series, eventname);
28434 }
28435
28436 // trigger any hover bind events
28437
28438 var pos = { pageX: e.pageX, pageY: e.pageY };
28439 target.trigger(eventname, [pos, item]);
28440 }
28441
28442 function highlight(s, auto) {
28443 //if (typeof s == "number") {
28444 // s = series[s];
28445 //}
28446
28447 var i = indexOfHighlight(s);
28448
28449 if (i == -1) {
28450 highlights.push({ series: s, auto: auto });
28451 plot.triggerRedrawOverlay();
28452 } else if (!auto) {
28453 highlights[i].auto = false;
28454 }
28455 }
28456
28457 function unhighlight(s) {
28458 if (s == null) {
28459 highlights = [];
28460 plot.triggerRedrawOverlay();
28461 }
28462
28463 //if (typeof s == "number") {
28464 // s = series[s];
28465 //}
28466
28467 var i = indexOfHighlight(s);
28468
28469 if (i != -1) {
28470 highlights.splice(i, 1);
28471 plot.triggerRedrawOverlay();
28472 }
28473 }
28474
28475 function indexOfHighlight(s) {
28476 for (var i = 0; i < highlights.length; ++i) {
28477 var h = highlights[i];
28478 if (h.series == s)
28479 return i;
28480 }
28481 return -1;
28482 }
28483
28484 function drawOverlay(plot, octx) {
28485
28486 var options = plot.getOptions();
28487
28488 var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
28489
28490 octx.save();
28491 octx.translate(centerLeft, centerTop);
28492 octx.scale(1, options.series.pie.tilt);
28493
28494 for (var i = 0; i < highlights.length; ++i) {
28495 drawHighlight(highlights[i].series);
28496 }
28497
28498 drawDonutHole(octx);
28499
28500 octx.restore();
28501
28502 function drawHighlight(series) {
28503
28504 if (series.angle <= 0 || isNaN(series.angle)) {
28505 return;
28506 }
28507
28508 //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
28509 octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor
28510 octx.beginPath();
28511 if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) {
28512 octx.moveTo(0, 0); // Center of the pie
28513 }
28514 octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false);
28515 octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false);
28516 octx.closePath();
28517 octx.fill();
28518 }
28519 }
28520 } // end init (plugin body)
28521
28522 // define pie specific options and their default values
28523
28524 var options = {
28525 series: {
28526 pie: {
28527 show: false,
28528 radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
28529 innerRadius: 0, /* for donut */
28530 startAngle: 3/2,
28531 tilt: 1,
28532 shadow: {
28533 left: 5, // shadow left offset
28534 top: 15, // shadow top offset
28535 alpha: 0.02 // shadow alpha
28536 },
28537 offset: {
28538 top: 0,
28539 left: "auto"
28540 },
28541 stroke: {
28542 color: "#fff",
28543 width: 1
28544 },
28545 label: {
28546 show: "auto",
28547 formatter: function(label, slice) {
28548 return "<div style='font-size:x-small;text-align:center;padding:2px;color:" + slice.color + ";'>" + label + "<br/>" + Math.round(slice.percent) + "%</div>";
28549 }, // formatter function
28550 radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
28551 background: {
28552 color: null,
28553 opacity: 0
28554 },
28555 threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow)
28556 },
28557 combine: {
28558 threshold: -1, // percentage at which to combine little slices into one larger slice
28559 color: null, // color to give the new slice (auto-generated if null)
28560 label: "Other" // label to give the new slice
28561 },
28562 highlight: {
28563 //color: "#fff", // will add this functionality once parseColor is available
28564 opacity: 0.5
28565 }
28566 }
28567 }
28568 };
28569
28570 $.plot.plugins.push({
28571 init: init,
28572 options: options,
28573 name: "pie",
28574 version: "1.1"
28575 });
28576
28577 })(jQuery);
28578 /* Flot plugin for automatically redrawing plots as the placeholder resizes.
28579
28580 Copyright (c) 2007-2013 IOLA and Ole Laursen.
28581 Licensed under the MIT license.
28582
28583 It works by listening for changes on the placeholder div (through the jQuery
28584 resize event plugin) - if the size changes, it will redraw the plot.
28585
28586 There are no options. If you need to disable the plugin for some plots, you
28587 can just fix the size of their placeholders.
28588
28589 */
28590
28591 /* Inline dependency:
28592 * jQuery resize event - v1.1 - 3/14/2010
28593 * http://benalman.com/projects/jquery-resize-plugin/
28594 *
28595 * Copyright (c) 2010 "Cowboy" Ben Alman
28596 * Dual licensed under the MIT and GPL licenses.
28597 * http://benalman.com/about/license/
28598 */
28599
28600 (function($,t,n){function p(){for(var n=r.length-1;n>=0;n--){var o=$(r[n]);if(o[0]==t||o.is(":visible")){var h=o.width(),d=o.height(),v=o.data(a);!v||h===v.w&&d===v.h?i[f]=i[l]:(i[f]=i[c],o.trigger(u,[v.w=h,v.h=d]))}else v=o.data(a),v.w=0,v.h=0}s!==null&&(s=t.requestAnimationFrame(p))}var r=[],i=$.resize=$.extend($.resize,{}),s,o="setTimeout",u="resize",a=u+"-special-event",f="delay",l="pendingDelay",c="activeDelay",h="throttleWindow";i[l]=250,i[c]=20,i[f]=i[l],i[h]=!0,$.event.special[u]={setup:function(){if(!i[h]&&this[o])return!1;var t=$(this);r.push(this),t.data(a,{w:t.width(),h:t.height()}),r.length===1&&(s=n,p())},teardown:function(){if(!i[h]&&this[o])return!1;var t=$(this);for(var n=r.length-1;n>=0;n--)if(r[n]==this){r.splice(n,1);break}t.removeData(a),r.length||(cancelAnimationFrame(s),s=null)},add:function(t){function s(t,i,s){var o=$(this),u=o.data(a);u.w=i!==n?i:o.width(),u.h=s!==n?s:o.height(),r.apply(this,arguments)}if(!i[h]&&this[o])return!1;var r;if($.isFunction(t))return r=t,s;r=t.handler,t.handler=s}},t.requestAnimationFrame||(t.requestAnimationFrame=function(){return t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.oRequestAnimationFrame||t.msRequestAnimationFrame||function(e,n){return t.setTimeout(e,i[f])}}()),t.cancelAnimationFrame||(t.cancelAnimationFrame=function(){return t.webkitCancelRequestAnimationFrame||t.mozCancelRequestAnimationFrame||t.oCancelRequestAnimationFrame||t.msCancelRequestAnimationFrame||clearTimeout}())})(jQuery,this);
28601
28602 (function ($) {
28603 var options = { }; // no options
28604
28605 function init(plot) {
28606 function onResize() {
28607 var placeholder = plot.getPlaceholder();
28608
28609 // somebody might have hidden us and we can't plot
28610 // when we don't have the dimensions
28611 if (placeholder.width() == 0 || placeholder.height() == 0)
28612 return;
28613
28614 plot.resize();
28615 plot.setupGrid();
28616 plot.draw();
28617 }
28618
28619 function bindEvents(plot, eventHolder) {
28620 plot.getPlaceholder().resize(onResize);
28621 }
28622
28623 function shutdown(plot, eventHolder) {
28624 plot.getPlaceholder().unbind("resize", onResize);
28625 }
28626
28627 plot.hooks.bindEvents.push(bindEvents);
28628 plot.hooks.shutdown.push(shutdown);
28629 }
28630
28631 $.plot.plugins.push({
28632 init: init,
28633 options: options,
28634 name: 'resize',
28635 version: '1.0'
28636 });
28637 })(jQuery);
28638 /* Flot plugin for selecting regions of a plot.
28639
28640 Copyright (c) 2007-2013 IOLA and Ole Laursen.
28641 Licensed under the MIT license.
28642
28643 The plugin supports these options:
28644
28645 selection: {
28646 mode: null or "x" or "y" or "xy",
28647 color: color,
28648 shape: "round" or "miter" or "bevel",
28649 minSize: number of pixels
28650 }
28651
28652 Selection support is enabled by setting the mode to one of "x", "y" or "xy".
28653 In "x" mode, the user will only be able to specify the x range, similarly for
28654 "y" mode. For "xy", the selection becomes a rectangle where both ranges can be
28655 specified. "color" is color of the selection (if you need to change the color
28656 later on, you can get to it with plot.getOptions().selection.color). "shape"
28657 is the shape of the corners of the selection.
28658
28659 "minSize" is the minimum size a selection can be in pixels. This value can
28660 be customized to determine the smallest size a selection can be and still
28661 have the selection rectangle be displayed. When customizing this value, the
28662 fact that it refers to pixels, not axis units must be taken into account.
28663 Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
28664 minute, setting "minSize" to 1 will not make the minimum selection size 1
28665 minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
28666 "plotunselected" events from being fired when the user clicks the mouse without
28667 dragging.
28668
28669 When selection support is enabled, a "plotselected" event will be emitted on
28670 the DOM element you passed into the plot function. The event handler gets a
28671 parameter with the ranges selected on the axes, like this:
28672
28673 placeholder.bind( "plotselected", function( event, ranges ) {
28674 alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
28675 // similar for yaxis - with multiple axes, the extra ones are in
28676 // x2axis, x3axis, ...
28677 });
28678
28679 The "plotselected" event is only fired when the user has finished making the
28680 selection. A "plotselecting" event is fired during the process with the same
28681 parameters as the "plotselected" event, in case you want to know what's
28682 happening while it's happening,
28683
28684 A "plotunselected" event with no arguments is emitted when the user clicks the
28685 mouse to remove the selection. As stated above, setting "minSize" to 0 will
28686 destroy this behavior.
28687
28688 The plugin allso adds the following methods to the plot object:
28689
28690 - setSelection( ranges, preventEvent )
28691
28692 Set the selection rectangle. The passed in ranges is on the same form as
28693 returned in the "plotselected" event. If the selection mode is "x", you
28694 should put in either an xaxis range, if the mode is "y" you need to put in
28695 an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
28696 this:
28697
28698 setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
28699
28700 setSelection will trigger the "plotselected" event when called. If you don't
28701 want that to happen, e.g. if you're inside a "plotselected" handler, pass
28702 true as the second parameter. If you are using multiple axes, you can
28703 specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
28704 xaxis, the plugin picks the first one it sees.
28705
28706 - clearSelection( preventEvent )
28707
28708 Clear the selection rectangle. Pass in true to avoid getting a
28709 "plotunselected" event.
28710
28711 - getSelection()
28712
28713 Returns the current selection in the same format as the "plotselected"
28714 event. If there's currently no selection, the function returns null.
28715
28716 */
28717
28718 (function ($) {
28719 function init(plot) {
28720 var selection = {
28721 first: { x: -1, y: -1}, second: { x: -1, y: -1},
28722 show: false,
28723 active: false
28724 };
28725
28726 // FIXME: The drag handling implemented here should be
28727 // abstracted out, there's some similar code from a library in
28728 // the navigation plugin, this should be massaged a bit to fit
28729 // the Flot cases here better and reused. Doing this would
28730 // make this plugin much slimmer.
28731 var savedhandlers = {};
28732
28733 var mouseUpHandler = null;
28734
28735 function onMouseMove(e) {
28736 if (selection.active) {
28737 updateSelection(e);
28738
28739 plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
28740 }
28741 }
28742
28743 function onMouseDown(e) {
28744 if (e.which != 1) // only accept left-click
28745 return;
28746
28747 // cancel out any text selections
28748 document.body.focus();
28749
28750 // prevent text selection and drag in old-school browsers
28751 if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
28752 savedhandlers.onselectstart = document.onselectstart;
28753 document.onselectstart = function () { return false; };
28754 }
28755 if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
28756 savedhandlers.ondrag = document.ondrag;
28757 document.ondrag = function () { return false; };
28758 }
28759
28760 setSelectionPos(selection.first, e);
28761
28762 selection.active = true;
28763
28764 // this is a bit silly, but we have to use a closure to be
28765 // able to whack the same handler again
28766 mouseUpHandler = function (e) { onMouseUp(e); };
28767
28768 $(document).one("mouseup", mouseUpHandler);
28769 }
28770
28771 function onMouseUp(e) {
28772 mouseUpHandler = null;
28773
28774 // revert drag stuff for old-school browsers
28775 if (document.onselectstart !== undefined)
28776 document.onselectstart = savedhandlers.onselectstart;
28777 if (document.ondrag !== undefined)
28778 document.ondrag = savedhandlers.ondrag;
28779
28780 // no more dragging
28781 selection.active = false;
28782 updateSelection(e);
28783
28784 if (selectionIsSane())
28785 triggerSelectedEvent();
28786 else {
28787 // this counts as a clear
28788 plot.getPlaceholder().trigger("plotunselected", [ ]);
28789 plot.getPlaceholder().trigger("plotselecting", [ null ]);
28790 }
28791
28792 return false;
28793 }
28794
28795 function getSelection() {
28796 if (!selectionIsSane())
28797 return null;
28798
28799 if (!selection.show) return null;
28800
28801 var r = {}, c1 = selection.first, c2 = selection.second;
28802 $.each(plot.getAxes(), function (name, axis) {
28803 if (axis.used) {
28804 var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]);
28805 r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
28806 }
28807 });
28808 return r;
28809 }
28810
28811 function triggerSelectedEvent() {
28812 var r = getSelection();
28813
28814 plot.getPlaceholder().trigger("plotselected", [ r ]);
28815
28816 // backwards-compat stuff, to be removed in future
28817 if (r.xaxis && r.yaxis)
28818 plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
28819 }
28820
28821 function clamp(min, value, max) {
28822 return value < min ? min: (value > max ? max: value);
28823 }
28824
28825 function setSelectionPos(pos, e) {
28826 var o = plot.getOptions();
28827 var offset = plot.getPlaceholder().offset();
28828 var plotOffset = plot.getPlotOffset();
28829 pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
28830 pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
28831
28832 if (o.selection.mode == "y")
28833 pos.x = pos == selection.first ? 0 : plot.width();
28834
28835 if (o.selection.mode == "x")
28836 pos.y = pos == selection.first ? 0 : plot.height();
28837 }
28838
28839 function updateSelection(pos) {
28840 if (pos.pageX == null)
28841 return;
28842
28843 setSelectionPos(selection.second, pos);
28844 if (selectionIsSane()) {
28845 selection.show = true;
28846 plot.triggerRedrawOverlay();
28847 }
28848 else
28849 clearSelection(true);
28850 }
28851
28852 function clearSelection(preventEvent) {
28853 if (selection.show) {
28854 selection.show = false;
28855 plot.triggerRedrawOverlay();
28856 if (!preventEvent)
28857 plot.getPlaceholder().trigger("plotunselected", [ ]);
28858 }
28859 }
28860
28861 // function taken from markings support in Flot
28862 function extractRange(ranges, coord) {
28863 var axis, from, to, key, axes = plot.getAxes();
28864
28865 for (var k in axes) {
28866 axis = axes[k];
28867 if (axis.direction == coord) {
28868 key = coord + axis.n + "axis";
28869 if (!ranges[key] && axis.n == 1)
28870 key = coord + "axis"; // support x1axis as xaxis
28871 if (ranges[key]) {
28872 from = ranges[key].from;
28873 to = ranges[key].to;
28874 break;
28875 }
28876 }
28877 }
28878
28879 // backwards-compat stuff - to be removed in future
28880 if (!ranges[key]) {
28881 axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
28882 from = ranges[coord + "1"];
28883 to = ranges[coord + "2"];
28884 }
28885
28886 // auto-reverse as an added bonus
28887 if (from != null && to != null && from > to) {
28888 var tmp = from;
28889 from = to;
28890 to = tmp;
28891 }
28892
28893 return { from: from, to: to, axis: axis };
28894 }
28895
28896 function setSelection(ranges, preventEvent) {
28897 var axis, range, o = plot.getOptions();
28898
28899 if (o.selection.mode == "y") {
28900 selection.first.x = 0;
28901 selection.second.x = plot.width();
28902 }
28903 else {
28904 range = extractRange(ranges, "x");
28905
28906 selection.first.x = range.axis.p2c(range.from);
28907 selection.second.x = range.axis.p2c(range.to);
28908 }
28909
28910 if (o.selection.mode == "x") {
28911 selection.first.y = 0;
28912 selection.second.y = plot.height();
28913 }
28914 else {
28915 range = extractRange(ranges, "y");
28916
28917 selection.first.y = range.axis.p2c(range.from);
28918 selection.second.y = range.axis.p2c(range.to);
28919 }
28920
28921 selection.show = true;
28922 plot.triggerRedrawOverlay();
28923 if (!preventEvent && selectionIsSane())
28924 triggerSelectedEvent();
28925 }
28926
28927 function selectionIsSane() {
28928 var minSize = plot.getOptions().selection.minSize;
28929 return Math.abs(selection.second.x - selection.first.x) >= minSize &&
28930 Math.abs(selection.second.y - selection.first.y) >= minSize;
28931 }
28932
28933 plot.clearSelection = clearSelection;
28934 plot.setSelection = setSelection;
28935 plot.getSelection = getSelection;
28936
28937 plot.hooks.bindEvents.push(function(plot, eventHolder) {
28938 var o = plot.getOptions();
28939 if (o.selection.mode != null) {
28940 eventHolder.mousemove(onMouseMove);
28941 eventHolder.mousedown(onMouseDown);
28942 }
28943 });
28944
28945
28946 plot.hooks.drawOverlay.push(function (plot, ctx) {
28947 // draw selection
28948 if (selection.show && selectionIsSane()) {
28949 var plotOffset = plot.getPlotOffset();
28950 var o = plot.getOptions();
28951
28952 ctx.save();
28953 ctx.translate(plotOffset.left, plotOffset.top);
28954
28955 var c = $.color.parse(o.selection.color);
28956
28957 ctx.strokeStyle = c.scale('a', 0.8).toString();
28958 ctx.lineWidth = 1;
28959 ctx.lineJoin = o.selection.shape;
28960 ctx.fillStyle = c.scale('a', 0.4).toString();
28961
28962 var x = Math.min(selection.first.x, selection.second.x) + 0.5,
28963 y = Math.min(selection.first.y, selection.second.y) + 0.5,
28964 w = Math.abs(selection.second.x - selection.first.x) - 1,
28965 h = Math.abs(selection.second.y - selection.first.y) - 1;
28966
28967 ctx.fillRect(x, y, w, h);
28968 ctx.strokeRect(x, y, w, h);
28969
28970 ctx.restore();
28971 }
28972 });
28973
28974 plot.hooks.shutdown.push(function (plot, eventHolder) {
28975 eventHolder.unbind("mousemove", onMouseMove);
28976 eventHolder.unbind("mousedown", onMouseDown);
28977
28978 if (mouseUpHandler)
28979 $(document).unbind("mouseup", mouseUpHandler);
28980 });
28981
28982 }
28983
28984 $.plot.plugins.push({
28985 init: init,
28986 options: {
28987 selection: {
28988 mode: null, // one of null, "x", "y" or "xy"
28989 color: "#e8cfac",
28990 shape: "round", // one of "round", "miter", or "bevel"
28991 minSize: 5 // minimum number of pixels
28992 }
28993 },
28994 name: 'selection',
28995 version: '1.1'
28996 });
28997 })(jQuery);
28998 /* Pretty handling of time axes.
28999
29000 Copyright (c) 2007-2013 IOLA and Ole Laursen.
29001 Licensed under the MIT license.
29002
29003 Set axis.mode to "time" to enable. See the section "Time series data" in
29004 API.txt for details.
29005
29006 */
29007
29008 (function($) {
29009
29010 var options = {
29011 xaxis: {
29012 timezone: null, // "browser" for local to the client or timezone for timezone-js
29013 timeformat: null, // format string to use
29014 twelveHourClock: false, // 12 or 24 time in time mode
29015 monthNames: null // list of names of months
29016 }
29017 };
29018
29019 // round to nearby lower multiple of base
29020
29021 function floorInBase(n, base) {
29022 return base * Math.floor(n / base);
29023 }
29024
29025 // Returns a string with the date d formatted according to fmt.
29026 // A subset of the Open Group's strftime format is supported.
29027
29028 function formatDate(d, fmt, monthNames, dayNames) {
29029
29030 if (typeof d.strftime == "function") {
29031 return d.strftime(fmt);
29032 }
29033
29034 var leftPad = function(n, pad) {
29035 n = "" + n;
29036 pad = "" + (pad == null ? "0" : pad);
29037 return n.length == 1 ? pad + n : n;
29038 };
29039
29040 var r = [];
29041 var escape = false;
29042 var hours = d.getHours();
29043 var isAM = hours < 12;
29044
29045 if (monthNames == null) {
29046 monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
29047 }
29048
29049 if (dayNames == null) {
29050 dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
29051 }
29052
29053 var hours12;
29054
29055 if (hours > 12) {
29056 hours12 = hours - 12;
29057 } else if (hours == 0) {
29058 hours12 = 12;
29059 } else {
29060 hours12 = hours;
29061 }
29062
29063 for (var i = 0; i < fmt.length; ++i) {
29064
29065 var c = fmt.charAt(i);
29066
29067 if (escape) {
29068 switch (c) {
29069 case 'a': c = "" + dayNames[d.getDay()]; break;
29070 case 'b': c = "" + monthNames[d.getMonth()]; break;
29071 case 'd': c = leftPad(d.getDate()); break;
29072 case 'e': c = leftPad(d.getDate(), " "); break;
29073 case 'h': // For back-compat with 0.7; remove in 1.0
29074 case 'H': c = leftPad(hours); break;
29075 case 'I': c = leftPad(hours12); break;
29076 case 'l': c = leftPad(hours12, " "); break;
29077 case 'm': c = leftPad(d.getMonth() + 1); break;
29078 case 'M': c = leftPad(d.getMinutes()); break;
29079 // quarters not in Open Group's strftime specification
29080 case 'q':
29081 c = "" + (Math.floor(d.getMonth() / 3) + 1); break;
29082 case 'S': c = leftPad(d.getSeconds()); break;
29083 case 'y': c = leftPad(d.getFullYear() % 100); break;
29084 case 'Y': c = "" + d.getFullYear(); break;
29085 case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break;
29086 case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break;
29087 case 'w': c = "" + d.getDay(); break;
29088 }
29089 r.push(c);
29090 escape = false;
29091 } else {
29092 if (c == "%") {
29093 escape = true;
29094 } else {
29095 r.push(c);
29096 }
29097 }
29098 }
29099
29100 return r.join("");
29101 }
29102
29103 // To have a consistent view of time-based data independent of which time
29104 // zone the client happens to be in we need a date-like object independent
29105 // of time zones. This is done through a wrapper that only calls the UTC
29106 // versions of the accessor methods.
29107
29108 function makeUtcWrapper(d) {
29109
29110 function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) {
29111 sourceObj[sourceMethod] = function() {
29112 return targetObj[targetMethod].apply(targetObj, arguments);
29113 };
29114 };
29115
29116 var utc = {
29117 date: d
29118 };
29119
29120 // support strftime, if found
29121
29122 if (d.strftime != undefined) {
29123 addProxyMethod(utc, "strftime", d, "strftime");
29124 }
29125
29126 addProxyMethod(utc, "getTime", d, "getTime");
29127 addProxyMethod(utc, "setTime", d, "setTime");
29128
29129 var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"];
29130
29131 for (var p = 0; p < props.length; p++) {
29132 addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]);
29133 addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]);
29134 }
29135
29136 return utc;
29137 };
29138
29139 // select time zone strategy. This returns a date-like object tied to the
29140 // desired timezone
29141
29142 function dateGenerator(ts, opts) {
29143 if (opts.timezone == "browser") {
29144 return new Date(ts);
29145 } else if (!opts.timezone || opts.timezone == "utc") {
29146 return makeUtcWrapper(new Date(ts));
29147 } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") {
29148 var d = new timezoneJS.Date();
29149 // timezone-js is fickle, so be sure to set the time zone before
29150 // setting the time.
29151 d.setTimezone(opts.timezone);
29152 d.setTime(ts);
29153 return d;
29154 } else {
29155 return makeUtcWrapper(new Date(ts));
29156 }
29157 }
29158
29159 // map of app. size of time units in milliseconds
29160
29161 var timeUnitSize = {
29162 "second": 1000,
29163 "minute": 60 * 1000,
29164 "hour": 60 * 60 * 1000,
29165 "day": 24 * 60 * 60 * 1000,
29166 "month": 30 * 24 * 60 * 60 * 1000,
29167 "quarter": 3 * 30 * 24 * 60 * 60 * 1000,
29168 "year": 365.2425 * 24 * 60 * 60 * 1000
29169 };
29170
29171 // the allowed tick sizes, after 1 year we use
29172 // an integer algorithm
29173
29174 var baseSpec = [
29175 [1, "second"], [2, "second"], [5, "second"], [10, "second"],
29176 [30, "second"],
29177 [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"],
29178 [30, "minute"],
29179 [1, "hour"], [2, "hour"], [4, "hour"],
29180 [8, "hour"], [12, "hour"],
29181 [1, "day"], [2, "day"], [3, "day"],
29182 [0.25, "month"], [0.5, "month"], [1, "month"],
29183 [2, "month"]
29184 ];
29185
29186 // we don't know which variant(s) we'll need yet, but generating both is
29187 // cheap
29188
29189 var specMonths = baseSpec.concat([[3, "month"], [6, "month"],
29190 [1, "year"]]);
29191 var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"],
29192 [1, "year"]]);
29193
29194 function init(plot) {
29195 plot.hooks.processOptions.push(function (plot, options) {
29196 $.each(plot.getAxes(), function(axisName, axis) {
29197
29198 var opts = axis.options;
29199
29200 if (opts.mode == "time") {
29201 axis.tickGenerator = function(axis) {
29202
29203 var ticks = [];
29204 var d = dateGenerator(axis.min, opts);
29205 var minSize = 0;
29206
29207 // make quarter use a possibility if quarters are
29208 // mentioned in either of these options
29209
29210 var spec = (opts.tickSize && opts.tickSize[1] ===
29211 "quarter") ||
29212 (opts.minTickSize && opts.minTickSize[1] ===
29213 "quarter") ? specQuarters : specMonths;
29214
29215 if (opts.minTickSize != null) {
29216 if (typeof opts.tickSize == "number") {
29217 minSize = opts.tickSize;
29218 } else {
29219 minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]];
29220 }
29221 }
29222
29223 for (var i = 0; i < spec.length - 1; ++i) {
29224 if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]]
29225 + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2
29226 && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) {
29227 break;
29228 }
29229 }
29230
29231 var size = spec[i][0];
29232 var unit = spec[i][1];
29233
29234 // special-case the possibility of several years
29235
29236 if (unit == "year") {
29237
29238 // if given a minTickSize in years, just use it,
29239 // ensuring that it's an integer
29240
29241 if (opts.minTickSize != null && opts.minTickSize[1] == "year") {
29242 size = Math.floor(opts.minTickSize[0]);
29243 } else {
29244
29245 var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10));
29246 var norm = (axis.delta / timeUnitSize.year) / magn;
29247
29248 if (norm < 1.5) {
29249 size = 1;
29250 } else if (norm < 3) {
29251 size = 2;
29252 } else if (norm < 7.5) {
29253 size = 5;
29254 } else {
29255 size = 10;
29256 }
29257
29258 size *= magn;
29259 }
29260
29261 // minimum size for years is 1
29262
29263 if (size < 1) {
29264 size = 1;
29265 }
29266 }
29267
29268 axis.tickSize = opts.tickSize || [size, unit];
29269 var tickSize = axis.tickSize[0];
29270 unit = axis.tickSize[1];
29271
29272 var step = tickSize * timeUnitSize[unit];
29273
29274 if (unit == "second") {
29275 d.setSeconds(floorInBase(d.getSeconds(), tickSize));
29276 } else if (unit == "minute") {
29277 d.setMinutes(floorInBase(d.getMinutes(), tickSize));
29278 } else if (unit == "hour") {
29279 d.setHours(floorInBase(d.getHours(), tickSize));
29280 } else if (unit == "month") {
29281 d.setMonth(floorInBase(d.getMonth(), tickSize));
29282 } else if (unit == "quarter") {
29283 d.setMonth(3 * floorInBase(d.getMonth() / 3,
29284 tickSize));
29285 } else if (unit == "year") {
29286 d.setFullYear(floorInBase(d.getFullYear(), tickSize));
29287 }
29288
29289 // reset smaller components
29290
29291 d.setMilliseconds(0);
29292
29293 if (step >= timeUnitSize.minute) {
29294 d.setSeconds(0);
29295 }
29296 if (step >= timeUnitSize.hour) {
29297 d.setMinutes(0);
29298 }
29299 if (step >= timeUnitSize.day) {
29300 d.setHours(0);
29301 }
29302 if (step >= timeUnitSize.day * 4) {
29303 d.setDate(1);
29304 }
29305 if (step >= timeUnitSize.month * 2) {
29306 d.setMonth(floorInBase(d.getMonth(), 3));
29307 }
29308 if (step >= timeUnitSize.quarter * 2) {
29309 d.setMonth(floorInBase(d.getMonth(), 6));
29310 }
29311 if (step >= timeUnitSize.year) {
29312 d.setMonth(0);
29313 }
29314
29315 var carry = 0;
29316 var v = Number.NaN;
29317 var prev;
29318
29319 do {
29320
29321 prev = v;
29322 v = d.getTime();
29323 ticks.push(v);
29324
29325 if (unit == "month" || unit == "quarter") {
29326 if (tickSize < 1) {
29327
29328 // a bit complicated - we'll divide the
29329 // month/quarter up but we need to take
29330 // care of fractions so we don't end up in
29331 // the middle of a day
29332
29333 d.setDate(1);
29334 var start = d.getTime();
29335 d.setMonth(d.getMonth() +
29336 (unit == "quarter" ? 3 : 1));
29337 var end = d.getTime();
29338 d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize);
29339 carry = d.getHours();
29340 d.setHours(0);
29341 } else {
29342 d.setMonth(d.getMonth() +
29343 tickSize * (unit == "quarter" ? 3 : 1));
29344 }
29345 } else if (unit == "year") {
29346 d.setFullYear(d.getFullYear() + tickSize);
29347 } else {
29348 d.setTime(v + step);
29349 }
29350 } while (v < axis.max && v != prev);
29351
29352 return ticks;
29353 };
29354
29355 axis.tickFormatter = function (v, axis) {
29356
29357 var d = dateGenerator(v, axis.options);
29358
29359 // first check global format
29360
29361 if (opts.timeformat != null) {
29362 return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames);
29363 }
29364
29365 // possibly use quarters if quarters are mentioned in
29366 // any of these places
29367
29368 var useQuarters = (axis.options.tickSize &&
29369 axis.options.tickSize[1] == "quarter") ||
29370 (axis.options.minTickSize &&
29371 axis.options.minTickSize[1] == "quarter");
29372
29373 var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]];
29374 var span = axis.max - axis.min;
29375 var suffix = (opts.twelveHourClock) ? " %p" : "";
29376 var hourCode = (opts.twelveHourClock) ? "%I" : "%H";
29377 var fmt;
29378
29379 if (t < timeUnitSize.minute) {
29380 fmt = hourCode + ":%M:%S" + suffix;
29381 } else if (t < timeUnitSize.day) {
29382 if (span < 2 * timeUnitSize.day) {
29383 fmt = hourCode + ":%M" + suffix;
29384 } else {
29385 fmt = "%b %d " + hourCode + ":%M" + suffix;
29386 }
29387 } else if (t < timeUnitSize.month) {
29388 fmt = "%b %d";
29389 } else if ((useQuarters && t < timeUnitSize.quarter) ||
29390 (!useQuarters && t < timeUnitSize.year)) {
29391 if (span < timeUnitSize.year) {
29392 fmt = "%b";
29393 } else {
29394 fmt = "%b %Y";
29395 }
29396 } else if (useQuarters && t < timeUnitSize.year) {
29397 if (span < timeUnitSize.year) {
29398 fmt = "Q%q";
29399 } else {
29400 fmt = "Q%q %Y";
29401 }
29402 } else {
29403 fmt = "%Y";
29404 }
29405
29406 var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames);
29407
29408 return rt;
29409 };
29410 }
29411 });
29412 });
29413 }
29414
29415 $.plot.plugins.push({
29416 init: init,
29417 options: options,
29418 name: 'time',
29419 version: '1.0'
29420 });
29421
29422 // Time-axis support used to be in Flot core, which exposed the
29423 // formatDate function on the plot object. Various plugins depend
29424 // on the function, so we need to re-expose it here.
29425
29426 $.plot.formatDate = formatDate;
29427
29428 })(jQuery);
29429 /*
29430 * jquery.flot.tooltip
29431 *
29432 * description: easy-to-use tooltips for Flot charts
29433 * version: 0.6.5
29434 * author: Krzysztof Urbas @krzysu [myviews.pl]
29435 * website: https://github.com/krzysu/flot.tooltip
29436 *
29437 * build on 2014-01-23
29438 * released under MIT License, 2012
29439 */
29440 (function ($) {
29441
29442 // plugin options, default values
29443 var defaultOptions = {
29444 tooltip: false,
29445 tooltipOpts: {
29446 content: "%s | X: %x | Y: %y",
29447 // allowed templates are:
29448 // %s -> series label,
29449 // %x -> X value,
29450 // %y -> Y value,
29451 // %x.2 -> precision of X value,
29452 // %p -> percent
29453 xDateFormat: null,
29454 yDateFormat: null,
29455 monthNames: null,
29456 dayNames: null,
29457 shifts: {
29458 x: 10,
29459 y: 20
29460 },
29461 defaultTheme: true,
29462
29463 // callbacks
29464 onHover: function(flotItem, $tooltipEl) {}
29465 }
29466 };
29467
29468 // object
29469 var FlotTooltip = function(plot) {
29470
29471 // variables
29472 this.tipPosition = {x: 0, y: 0};
29473
29474 this.init(plot);
29475 };
29476
29477 // main plugin function
29478 FlotTooltip.prototype.init = function(plot) {
29479
29480 var that = this;
29481
29482 plot.hooks.bindEvents.push(function (plot, eventHolder) {
29483
29484 // get plot options
29485 that.plotOptions = plot.getOptions();
29486
29487 // if not enabled return
29488 if (that.plotOptions.tooltip === false || typeof that.plotOptions.tooltip === 'undefined') return;
29489
29490 // shortcut to access tooltip options
29491 that.tooltipOptions = that.plotOptions.tooltipOpts;
29492
29493 // create tooltip DOM element
29494 var $tip = that.getDomElement();
29495
29496 // bind event
29497 $( plot.getPlaceholder() ).bind("plothover", plothover);
29498
29499 $(eventHolder).bind('mousemove', mouseMove);
29500 });
29501
29502 plot.hooks.shutdown.push(function (plot, eventHolder){
29503 $(plot.getPlaceholder()).unbind("plothover", plothover);
29504 $(eventHolder).unbind("mousemove", mouseMove);
29505 });
29506
29507 function mouseMove(e){
29508 var pos = {};
29509 pos.x = e.pageX;
29510 pos.y = e.pageY;
29511 that.updateTooltipPosition(pos);
29512 }
29513
29514 function plothover(event, pos, item) {
29515 var $tip = that.getDomElement();
29516 if (item) {
29517 var tipText;
29518
29519 // convert tooltip content template to real tipText
29520 tipText = that.stringFormat(that.tooltipOptions.content, item);
29521
29522 $tip.html( tipText );
29523 that.updateTooltipPosition({ x: pos.pageX, y: pos.pageY });
29524 $tip.css({
29525 left: that.tipPosition.x + that.tooltipOptions.shifts.x,
29526 top: that.tipPosition.y + that.tooltipOptions.shifts.y
29527 })
29528 .show();
29529
29530 // run callback
29531 if(typeof that.tooltipOptions.onHover === 'function') {
29532 that.tooltipOptions.onHover(item, $tip);
29533 }
29534 }
29535 else {
29536 $tip.hide().html('');
29537 }
29538 }
29539 };
29540
29541 /**
29542 * get or create tooltip DOM element
29543 * @return jQuery object
29544 */
29545 FlotTooltip.prototype.getDomElement = function() {
29546 var $tip;
29547
29548 if( $('#flotTip').length > 0 ){
29549 $tip = $('#flotTip');
29550 }
29551 else {
29552 $tip = $('<div />').attr('id', 'flotTip');
29553 $tip.appendTo('body').hide().css({position: 'absolute'});
29554
29555 if(this.tooltipOptions.defaultTheme) {
29556 $tip.css({
29557 'background': '#fff',
29558 'z-index': '100',
29559 'padding': '0.4em 0.6em',
29560 'border-radius': '0.5em',
29561 'font-size': '0.8em',
29562 'border': '1px solid #111',
29563 'display': 'none',
29564 'white-space': 'nowrap'
29565 });
29566 }
29567 }
29568
29569 return $tip;
29570 };
29571
29572 // as the name says
29573 FlotTooltip.prototype.updateTooltipPosition = function(pos) {
29574 var totalTipWidth = $("#flotTip").outerWidth() + this.tooltipOptions.shifts.x;
29575 var totalTipHeight = $("#flotTip").outerHeight() + this.tooltipOptions.shifts.y;
29576 if ((pos.x - $(window).scrollLeft()) > ($(window).innerWidth() - totalTipWidth)) {
29577 pos.x -= totalTipWidth;
29578 }
29579 if ((pos.y - $(window).scrollTop()) > ($(window).innerHeight() - totalTipHeight)) {
29580 pos.y -= totalTipHeight;
29581 }
29582 this.tipPosition.x = pos.x;
29583 this.tipPosition.y = pos.y;
29584 };
29585
29586 /**
29587 * core function, create tooltip content
29588 * @param {string} content - template with tooltip content
29589 * @param {object} item - Flot item
29590 * @return {string} real tooltip content for current item
29591 */
29592 FlotTooltip.prototype.stringFormat = function(content, item) {
29593
29594 var percentPattern = /%p\.{0,1}(\d{0,})/;
29595 var seriesPattern = /%s/;
29596 var xPattern = /%x\.{0,1}(\d{0,})/;
29597 var yPattern = /%y\.{0,1}(\d{0,})/;
29598 var xPatternWithoutPrecision = "%x";
29599 var yPatternWithoutPrecision = "%y";
29600
29601 var x, y;
29602
29603 // for threshold plugin we need to read data from different place
29604 if (typeof item.series.threshold !== "undefined") {
29605 x = item.datapoint[0];
29606 y = item.datapoint[1];
29607 } else {
29608 x = item.series.data[item.dataIndex][0];
29609 y = item.series.data[item.dataIndex][1];
29610 }
29611
29612 // I think this is only in case of threshold plugin
29613 if (item.series.label === null && item.series.originSeries) {
29614 item.series.label = item.series.originSeries.label;
29615 }
29616
29617 // if it is a function callback get the content string
29618 if( typeof(content) === 'function' ) {
29619 content = content(item.series.label, x, y, item);
29620 }
29621
29622 // percent match for pie charts
29623 if( typeof (item.series.percent) !== 'undefined' ) {
29624 content = this.adjustValPrecision(percentPattern, content, item.series.percent);
29625 }
29626
29627 // series match
29628 if( typeof(item.series.label) !== 'undefined' ) {
29629 content = content.replace(seriesPattern, item.series.label);
29630 }
29631 else {
29632 //remove %s if label is undefined
29633 content = content.replace(seriesPattern, "");
29634 }
29635
29636 // time mode axes with custom dateFormat
29637 if(this.isTimeMode('xaxis', item) && this.isXDateFormat(item)) {
29638 content = content.replace(xPattern, this.timestampToDate(x, this.tooltipOptions.xDateFormat));
29639 }
29640
29641 if(this.isTimeMode('yaxis', item) && this.isYDateFormat(item)) {
29642 content = content.replace(yPattern, this.timestampToDate(y, this.tooltipOptions.yDateFormat));
29643 }
29644
29645 // set precision if defined
29646 if(typeof x === 'number') {
29647 content = this.adjustValPrecision(xPattern, content, x);
29648 }
29649 if(typeof y === 'number') {
29650 content = this.adjustValPrecision(yPattern, content, y);
29651 }
29652
29653 // change x from number to given label, if given
29654 if(typeof item.series.xaxis.ticks !== 'undefined') {
29655 if(item.series.xaxis.ticks.length > item.dataIndex && !this.isTimeMode('xaxis', item))
29656 content = content.replace(xPattern, item.series.xaxis.ticks[item.dataIndex].label);
29657 }
29658 // if no value customization, use tickFormatter by default
29659 if(typeof item.series.xaxis.tickFormatter !== 'undefined') {
29660 //escape dollar
29661 content = content.replace(xPatternWithoutPrecision, item.series.xaxis.tickFormatter(x, item.series.xaxis).replace(/\$/g, '$$'));
29662 }
29663 if(typeof item.series.yaxis.tickFormatter !== 'undefined') {
29664 //escape dollar
29665 content = content.replace(yPatternWithoutPrecision, item.series.yaxis.tickFormatter(y, item.series.yaxis).replace(/\$/g, '$$'));
29666 }
29667
29668 return content;
29669 };
29670
29671 // helpers just for readability
29672 FlotTooltip.prototype.isTimeMode = function(axisName, item) {
29673 return (typeof item.series[axisName].options.mode !== 'undefined' && item.series[axisName].options.mode === 'time');
29674 };
29675
29676 FlotTooltip.prototype.isXDateFormat = function(item) {
29677 return (typeof this.tooltipOptions.xDateFormat !== 'undefined' && this.tooltipOptions.xDateFormat !== null);
29678 };
29679
29680 FlotTooltip.prototype.isYDateFormat = function(item) {
29681 return (typeof this.tooltipOptions.yDateFormat !== 'undefined' && this.tooltipOptions.yDateFormat !== null);
29682 };
29683
29684 //
29685 FlotTooltip.prototype.timestampToDate = function(tmst, dateFormat) {
29686 var theDate = new Date(tmst*1);
29687 return $.plot.formatDate(theDate, dateFormat, this.tooltipOptions.monthNames, this.tooltipOptions.dayNames);
29688 };
29689
29690 //
29691 FlotTooltip.prototype.adjustValPrecision = function(pattern, content, value) {
29692
29693 var precision;
29694 var matchResult = content.match(pattern);
29695 if( matchResult !== null ) {
29696 if(RegExp.$1 !== '') {
29697 precision = RegExp.$1;
29698 value = value.toFixed(precision);
29699
29700 // only replace content if precision exists, in other case use thickformater
29701 content = content.replace(pattern, value);
29702 }
29703 }
29704 return content;
29705 };
29706
29707 //
29708 var init = function(plot) {
29709 new FlotTooltip(plot);
29710 };
29711
29712 // define Flot plugin
29713 $.plot.plugins.push({
29714 init: init,
29715 options: defaultOptions,
29716 name: 'tooltip',
29717 version: '0.6.1'
29718 });
29719
29720 })(jQuery);
29721 // SIMILE is not used anymore (and messes with jQuery!) so it was removed
29722 // TimeplotLoader.load(GeoTemCoLoader.urlPrefix + 'lib/', GeoTemCoLoader.loadScripts);
29723
29724 // ..but we still need (and use) the following defines, that where copied from there
29725 /* string.js */
29726 String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"");
29727 };
29728 String.prototype.startsWith=function(A){return this.length>=A.length&&this.substr(0,A.length)==A;
29729 };
29730 String.prototype.endsWith=function(A){return this.length>=A.length&&this.substr(this.length-A.length)==A;
29731 };
29732 String.substitute=function(B,D){var A="";
29733 var F=0;
29734 while(F<B.length-1){var C=B.indexOf("%",F);
29735 if(C<0||C==B.length-1){break;
29736 }else{if(C>F&&B.charAt(C-1)=="\\"){A+=B.substring(F,C-1)+"%";
29737 F=C+1;
29738 }else{var E=parseInt(B.charAt(C+1));
29739 if(isNaN(E)||E>=D.length){A+=B.substring(F,C+2);
29740 }else{A+=B.substring(F,C)+D[E].toString();
29741 }F=C+2;
29742 }}}if(F<B.length){A+=B.substring(F);
29743 }return A;
29744 };
29745
29746 /* date-time.js */
29747 SimileAjax=new Object();
29748 SimileAjax.DateTime=new Object();
29749 SimileAjax.DateTime.MILLISECOND=0;
29750 SimileAjax.DateTime.SECOND=1;
29751 SimileAjax.DateTime.MINUTE=2;
29752 SimileAjax.DateTime.HOUR=3;
29753 SimileAjax.DateTime.DAY=4;
29754 SimileAjax.DateTime.WEEK=5;
29755 SimileAjax.DateTime.MONTH=6;
29756 SimileAjax.DateTime.YEAR=7;
29757 SimileAjax.DateTime.DECADE=8;
29758 SimileAjax.DateTime.CENTURY=9;
29759 SimileAjax.DateTime.MILLENNIUM=10;
29760 SimileAjax.DateTime.EPOCH=-1;
29761 SimileAjax.DateTime.ERA=-2;
29762
29763 SimileAjax.includeCssFile = function(doc, url) {
29764 var link = doc.createElement("link");
29765 link.setAttribute("rel", "stylesheet");
29766 link.setAttribute("type", "text/css");
29767 link.setAttribute("href", url);
29768 doc.getElementsByTagName("head")[0].appendChild(link);
29769 };
29770 /*
29771 * Tooltips.js
29772 *
29773 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
29774 *
29775 * This library is free software; you can redistribute it and/or
29776 * modify it under the terms of the GNU Lesser General Public
29777 * License as published by the Free Software Foundation; either
29778 * version 3 of the License, or (at your option) any later version.
29779 *
29780 * This library is distributed in the hope that it will be useful,
29781 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29782 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29783 * Lesser General Public License for more details.
29784 *
29785 * You should have received a copy of the GNU Lesser General Public
29786 * License along with this library; if not, write to the Free Software
29787 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
29788 * MA 02110-1301 USA
29789 */
29790
29791 /**
29792 * Tooltips JSON
29793 * GeoTemCo tooltips definition file
29794 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
29795 * @release 1.0
29796 * @release date: 2012-07-27
29797 * @version date: 2012-07-27
29798 */
29799 var Tooltips = {
29800 "en" : {
29801 "locationType" : "Location type",
29802 "selectLocationType" : "Select location type",
29803 "mapType" : "Background map",
29804 "selectMapType" : "Select background map",
29805 "selectOverlay" : "Select layer for spatial filtering",
29806 "overlays" : "Select layer",
29807 "mapSelectorTools" : "Map selector tools",
29808 "overlaySelector" : "Selection layer",
29809 "square" : "Square selection: Mouse down for the center and mouse move to set square bounds",
29810 "circle" : "Circle selection: Mouse down for the center and mouse move to set circle radius",
29811 "polygon" : "Polygon selection: Click to add vertex and double click to complete the polygon",
29812 "country" : "Country selection: Click inside the political borders of a country",
29813 "singleEntry" : "Only 1 entry available",
29814 "resultsLocation" : "with location information",
29815 "home" : "Reset map to initial view",
29816 "zoomIn" : "Zoom in",
29817 "zoomOut" : "Zoom out",
29818 "zoomSlider" : "Zoom slider",
29819 "dragSelection" : "Drag&Drop shape",
29820 "zoomSelection" : "Zoom into selection",
29821 "clearSelection" : "Clear selection",
29822 "contemporaryMap" : "Contemporary Map",
29823 "activateGeoLocation" : "Show my location",
29824 "deactivateGeoLocation" : "Hide my location",
29825 "mapOf" : "Map of",
29826 "close" : "Close",
29827 "genericBinning" : "delaunay",
29828 "squareBinning" : "square",
29829 "hexagonalBinning" : "hexagonal",
29830 "triangularBinning" : "triangular",
29831 "noBinning" : "none",
29832 "selectBinningType" : "Select aggregation type",
29833 "binningType" : "Aggregation type",
29834 "binningTooltip" : "Select the aggregation type for the data sources",
29835 "results" : "results",
29836 "result" : "result",
29837 "timeType" : "Time type",
29838 "timeUnit" : "Time unit:",
29839 "selectTimeType" : "Select time type",
29840 "timeAnimation" : "Animation",
29841 "resultsTime" : "with time information",
29842 "animationDisabled" : "Animation control (disabled)",
29843 "animationPlay" : "Animate selected time range",
29844 "animationPause" : "Pause animation",
29845 "leftHandle" : "Drag&Drop left border",
29846 "rightHandle" : "Drag&Drop right border",
29847 "dragTimeRange" : "Drag&Drop time range",
29848 "connectionsOn" : "Switch on time-dependent connections between map circles",
29849 "connectionsOff" : "Switch off time-dependent connections",
29850 "timeFeather" : "Adjust time range feather to smoothen map animations",
29851 "allResults" : "all",
29852 "pageInfo" : "Page PAGE_ID of PAGES_ID",
29853 "resultsInfo" : "RESULTS_FROM_ID-RESULTS_TO_ID of RESULTS_ID Results",
29854 "otherResults" : "others",
29855 "mapAggregation" : "Aggregation",
29856 "aggregation" : "Circle aggregation",
29857 "noAggregation" : "No circle aggregation",
29858 "showBoxTitle" : "Boundingbox",
29859 "showBbox" : "Shows given Boundingbox extension",
29860 "hideBbox" : "Hides given Boundingbox extension",
29861 "spaceHelp" : "A point on the map corresponds to one or more objects from the result list. ",
29862 "timeHelp" : "On the timeline are the search results sorted by year. You can choose different time-based categories as basis for the representation.",
29863 "selectTablePageItemsHelp" : "Click to select all rows of this page",
29864 "deselectTablePageItemsHelp" : "Click to deselect all rows of this page",
29865 "selectAllTableItemsHelp" : "Click to select all rows of the table",
29866 "deselectAllTableItemsHelp" : "Click to deselect all rows of the table",
29867 "filter" : "Filter",
29868 "filterSelectedItemsHelp" : "Filter the selected items",
29869 "inverseFilterSelectedItemsHelp" : "Apply an inverse filter on the selected items removing them from the views",
29870 "undoFilterSelection" : "Undo the last filter / inverse filter",
29871 "cancelSelection" : "Discard the current selection (all items appear as deselected)",
29872 "showSelectedHelp" : "Show only elements within the selection",
29873 "selectByTextHelp" : "Select elements that contain the given text",
29874 "showAllElementsHelp" : "Show all elements",
29875 "paginationFirsPageHelp" : "Show first page",
29876 "paginationPreviousPageHelp" : "Show previous page",
29877 "paginationNextPageHelp" : "Show next page",
29878 "paginationLastPageHelp" : "Show last page",
29879 "sortAZHelp" : "Sort table elements ascending according this column",
29880 "sortZAHelp" : "Sort table elements descending according this column",
29881 "paginationDropdownHelp" : "Select number of elements per page",
29882 "selectTimeUnit" : "Select Time Unit",
29883 "valueScale" : "Value Scale",
29884 "linearPlot" : "Linear Value Scale",
29885 "logarithmicPlot" : "Logarithmic Value Scale",
29886 "playButton" : "Animate Selected Range",
29887 "pauseButton" : "Pause Animation",
29888 "createNewFromSelectedHelp" : "Create new dataset from selected values",
29889 "removeDatasetHelp" : "Remove this dataset",
29890 "exportDatasetHelp" : "Export this dataset to a KML file",
29891 "invertSelectionHelp" : "Invert the current selection"
29892 },
29893 "de" : {
29894 "locationType" : "Ortsfacette",
29895 "selectLocationType" : "W&auml;hle Ortsfacette",
29896 "mapType" : "Kartentyp",
29897 "selectMapType" : "W&auml;hle Kartentyp",
29898 "selectOverlay" : "Kartenauswahl f&uuml;r r&auml;mliches filtern",
29899 "overlays" : "W&auml;hle layer",
29900 "mapSelectorTools" : "Bereichsauswahl",
29901 "overlaySelector" : "Selection layer",
29902 "square" : "Quadratauswahl: Maus ziehen und loslassen um Mittelpunkt und Seitenl&auml;nge des Quadrats zu bestimmen",
29903 "circle" : "Kreisauswahl: Maus ziehen und loslassen um Mittelpunkt und Radius des Kreises zu bestimmen",
29904 "polygon" : "Polygonauswahl: Mausklick zum Hinzuf&uuml;gen eines Eckpunktes, Doppelklick zum Fertigstellen",
29905 "country" : "Landauswahl: Mausklick innerhalb politischer Grenze eines Landes",
29906 "singleEntry" : "Nur 1 Eintrag vorhanden",
29907 "resultsLocation" : "mit Geoinformation",
29908 "home" : "Zur&uuml;cksetzen zur initialen Sicht",
29909 "zoomIn" : "Vergr&ouml;&szlig;ern",
29910 "zoomOut" : "Verkleinern",
29911 "zoomSlider" : "Zoomregler",
29912 "dragSelection" : "Verschiebe Auswahl",
29913 "zoomSelection" : "Vergr&ouml;&szlig;ere Auswahl",
29914 "clearSelection" : "Entferne Auswahlbereich",
29915 "contemporaryMap" : "Aktuelle Weltkarte",
29916 "activateGeoLocation" : "Meinen Standort anzeigen",
29917 "deactivateGeoLocation" : "Meinen Standort ausblenden",
29918 "mapOf" : "Karte von",
29919 "close" : "Schliessen",
29920 "genericBinning" : "Generisch",
29921 "squareBinning" : "Quadrate",
29922 "hexagonalBinning" : "Hexagone",
29923 "triangularBinning" : "Dreiecke",
29924 "noBinning" : "Keine Bins",
29925 "selectBinningType" : "W&auml;hle Binningart",
29926 "binningTooltip" : "W&aunl;hle die Binninart f&uuml;r die Datenquellen",
29927 "binningType" : "Binningart",
29928 "results" : "Resultate",
29929 "result" : "Resultat",
29930 "timeType" : "Zeitfacette",
29931 "timeUnit" : "Zeiteinheit",
29932 "selectTimeType" : "W&auml;hle Zeitfacette",
29933 "timeAnimation" : "Animation",
29934 "resultsTime" : "mit Zeitinformation",
29935 "animationDisabled" : "Animationswerkzeug (deaktiviert)",
29936 "animationPlay" : "Animiere ausgew&auml;hlten Zeitbereich",
29937 "animationPause" : "Animation anhalten",
29938 "leftHandle" : "Verschiebe linke Grenze",
29939 "rightHandle" : "Verschiebe rechte Grenze",
29940 "dragTimeRange" : "Verschiebe Zeitbereich",
29941 "connectionsOn" : "Aktiviere zeitabhängige Verbindungen zwischen Kreisen auf der Karte",
29942 "connectionsOff" : "Deaktiviere zeitabhängige Verbindungen",
29943 "timeFeather" : "Ver&auml;ndere Zeitbereichs&uuml;berg&auml;nge zum Gl&auml;tten der Animation",
29944 "pageInfo" : "Seite PAGE_ID von PAGES_ID",
29945 "resultsInfo" : "RESULTS_FROM_ID-RESULTS_TO_ID von RESULTS_ID Ergebnissen",
29946 "allResults" : "alle",
29947 "otherResults" : "sonstige",
29948 "mapAggregation" : "Aggregation",
29949 "aggregation" : "Kreise aggregiert",
29950 "noAggregation" : "Kreise nicht aggregiert",
29951 "showBbox" : "Geografische Ausdehnung anzeigen",
29952 "hideBbox" : "Geografische Ausdehnung ausblenden",
29953 "spaceHelp" : "Jeder Punkt auf der Karte entspricht einem oder mehreren Objekten der Ergebnisliste. Sie k&ouml;nnen verschiedene ortsbezogene Kategorien als Grundlage f&uuml;r die Darstellung w&auml;hlen (Auswahlfeld <strong>Ortsfacette</strong>) und verschiedene Kartentypen. <br> Da es Objekte geben kann, die keine Ortsangabe in ihrer Beschreibung enthalten, ist die Menge der in der Karte dargestellten Objekte in der Regel kleiner als in der Ergebnisliste (Anzahl darstellbarer Objekte siehe rechts oben über der Karte). <br> Mit der Karte können Sie die Suchergebnisse weiter eingrenzen, indem Sie auf einen der Punkte klicken. Wählen Sie einen Ort aus und klicken Sie auf die kleine Lupe, um die Ergebnisliste so einzuschränken, dass nur noch die diesem Ort zugeordneten Objekte als Suchergebnis erscheinen. Mehr zur Karte im Benutzerhandbuch ...",
29954 "timeHelp" : "In der Zeitleiste sind die Suchergebnisse nach Jahren geordnet. Sie k&ouml;nnen verschiedene zeitbezogene Kategorien als Grundlage f&uuml;r die Darstellung w&auml;hlen (Auswahlfeld <strong>Zeitfacette</strong>). <br> Da es Objekte geben kann, die keine Zeitangabe in ihrer Beschreibung enthalten, ist die Zahl der in der Zeitleiste dargestellten Objekte in der Regel kleiner als in der Ergebnisliste. Die Angabe über darstellbare Objekte finden Sie rechts über der Zeitleiste. <br>Mit der Zeitleiste können Sie die Suchergebnisse weiter eingrenzen. Wählen Sie ein Jahr oder einen Zeitraum durch Klicken und Ziehen und klicken Sie auf die kleine Lupe. Die Ergebnisliste zeigt nur noch die Objekte in diesem Zeitraum. Mehr zur Zeitleiste im Benutzerhandbuch ...",
29955 "selectTablePageItemsHelp" : "Click to select all rows of this page",
29956 "deselectTablePageItemsHelp" : "Click to deselect all rows of this page",
29957 "selectAllTableItemsHelp" : "Click to select all rows of the table",
29958 "deselectAllTableItemsHelp" : "Click to deselect all rows of the table",
29959 "filter" : "Filter",
29960 "filterSelectedItemsHelp" : "Filter the selected items",
29961 "inverseFilterSelectedItemsHelp" : "Apply an inverse filter on the selected items removing them from the views",
29962 "undoFilterSelection" : "Undo the last filter / inverse filter",
29963 "cancelSelection" : "Discard the current selection (all items appear as deselected)",
29964 "showSelectedHelp" : "Show only elements within the selection",
29965 "selectByTextHelp" : "Select elements that contain the given text",
29966 "showAllElementsHelp" : "Show all elements",
29967 "paginationFirsPageHelp" : "Show first page",
29968 "paginationPreviousPageHelp" : "Show previous page",
29969 "paginationNextPageHelp" : "Show next page",
29970 "paginationLastPageHelp" : "Show last page",
29971 "sortAZHelp" : "Sort table elements ascending according this column",
29972 "sortZAHelp" : "Sort table elements descending according this column",
29973 "paginationDropdownHelp" : "Select number of elements per page",
29974 "selectTimeUnit" : "W&auml;hle Zeitinervalle",
29975 "valueScale" : "Value Scale",
29976 "linearPlot" : "Linear Value Scale",
29977 "logarithmicPlot" : "Logarithmic Value Scale",
29978 "playButton" : "Animate Selected Range",
29979 "pauseButton" : "Pause Animation",
29980 "createNewFromSelectedHelp" : "Erstelle neuen Datensatz aus den selektierten Eintr&auml;gen",
29981 "removeDatasetHelp" : "Diesen Datensatz entfernen",
29982 "exportDatasetHelp" : "Diesen Datensatz in KML Datei exportieren",
29983 "invertSelectionHelp" : "Jetzige Selektion umkehren"
29984 }
29985 }
29986 /*
29987 * GeoTemConfig.js
29988 *
29989 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
29990 *
29991 * This library is free software; you can redistribute it and/or
29992 * modify it under the terms of the GNU Lesser General Public
29993 * License as published by the Free Software Foundation; either
29994 * version 3 of the License, or (at your option) any later version.
29995 *
29996 * This library is distributed in the hope that it will be useful,
29997 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29998 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29999 * Lesser General Public License for more details.
30000 *
30001 * You should have received a copy of the GNU Lesser General Public
30002 * License along with this library; if not, write to the Free Software
30003 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
30004 * MA 02110-1301 USA
30005 */
30006
30007 /**
30008 * @class GeoTemConfig
30009 * Global GeoTemCo Configuration File
30010 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
30011 * @release 1.0
30012 * @release date: 2012-07-27
30013 * @version date: 2012-07-27
30014 */
30015
30016
30017 // credits: user76888, The Digital Gabeg (http://stackoverflow.com/questions/1539367)
30018 $.fn.cleanWhitespace = function() {
30019 textNodes = this.contents().filter( function() {
30020 return (this.nodeType == 3 && !/\S/.test(this.nodeValue));
30021 }).remove();
30022 return this;
30023 };
30024
30025 GeoTemConfig = {
30026
30027 incompleteData : true, // show/hide data with either temporal or spatial metadata
30028 inverseFilter : true, // if inverse filtering is offered
30029 mouseWheelZoom : true, // enable/disable zoom with mouse wheel on map & timeplot
30030 language : 'en', // default language of GeoTemCo
30031 allowFilter : true, // if filtering should be allowed
30032 highlightEvents : true, // if updates after highlight events
30033 selectionEvents : true, // if updates after selection events
30034 tableExportDataset : true, // export dataset to KML
30035 allowCustomColoring : false, // if DataObjects can have an own color (useful for weighted coloring)
30036 loadColorFromDataset : false, // if DataObject color should be loaded automatically (from column "color")
30037 //colors for several datasets; rgb1 will be used for selected objects, rgb0 for unselected
30038 colors : [{
30039 r1 : 255,
30040 g1 : 101,
30041 b1 : 0,
30042 r0 : 253,
30043 g0 : 229,
30044 b0 : 205
30045 }, {
30046 r1 : 144,
30047 g1 : 26,
30048 b1 : 255,
30049 r0 : 230,
30050 g0 : 225,
30051 b0 : 255
30052 }, {
30053 r1 : 0,
30054 g1 : 217,
30055 b1 : 0,
30056 r0 : 213,
30057 g0 : 255,
30058 b0 : 213
30059 }, {
30060 r1 : 240,
30061 g1 : 220,
30062 b1 : 0,
30063 r0 : 247,
30064 g0 : 244,
30065 b0 : 197
30066 }]
30067
30068 }
30069
30070 GeoTemConfig.ie = false;
30071 GeoTemConfig.ie8 = false;
30072
30073 GeoTemConfig.independentMapId = 0;
30074 GeoTemConfig.independentTimeId = 0;
30075
30076 if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) {
30077 GeoTemConfig.ie = true;
30078 var ieversion = new Number(RegExp.$1);
30079 if (ieversion == 8) {
30080 GeoTemConfig.ie8 = true;
30081 }
30082 }
30083
30084 GeoTemConfig.getIndependentId = function(target){
30085 if( target == 'map' ){
30086 return ++GeoTemConfig.independentMapId;
30087 }
30088 if( target == 'time' ){
30089 return ++GeoTemConfig.independentTimeId;
30090 }
30091 return 0;
30092 };
30093
30094 GeoTemConfig.setHexColor = function(hex,index,fill){
30095 var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
30096 if( fill ){
30097 GeoTemConfig.colors[index].r0 = parseInt(result[1], 16);
30098 GeoTemConfig.colors[index].g0 = parseInt(result[2], 16);
30099 GeoTemConfig.colors[index].b0 = parseInt(result[3], 16);
30100 }
30101 else {
30102 GeoTemConfig.colors[index].r1 = parseInt(result[1], 16);
30103 GeoTemConfig.colors[index].g1 = parseInt(result[2], 16);
30104 GeoTemConfig.colors[index].b1 = parseInt(result[3], 16);
30105 }
30106 }
30107
30108 GeoTemConfig.setRgbColor = function(r,g,b,index,fill){
30109 if( fill ){
30110 GeoTemConfig.colors[index].r0 = r;
30111 GeoTemConfig.colors[index].g0 = g;
30112 GeoTemConfig.colors[index].b0 = b;
30113 }
30114 else {
30115 GeoTemConfig.colors[index].r1 = r;
30116 GeoTemConfig.colors[index].g1 = g;
30117 GeoTemConfig.colors[index].b1 = b;
30118 }
30119 }
30120
30121 GeoTemConfig.configure = function(urlPrefix) {
30122 GeoTemConfig.urlPrefix = urlPrefix;
30123 GeoTemConfig.path = GeoTemConfig.urlPrefix + "images/";
30124 }
30125
30126 GeoTemConfig.applySettings = function(settings) {
30127 $.extend(this, settings);
30128 };
30129
30130 //Keeps track of how many colors where assigned yet.
30131 GeoTemConfig.assignedColorCount = 0;
30132 GeoTemConfig.getColor = function(id){
30133 if (typeof GeoTemConfig.datasets[id].color === "undefined"){
30134 var color;
30135
30136 while (true){
30137 if( GeoTemConfig.colors.length <= GeoTemConfig.assignedColorCount ){
30138 color = {
30139 r1 : Math.floor((Math.random()*255)+1),
30140 g1 : Math.floor((Math.random()*255)+1),
30141 b1 : Math.floor((Math.random()*255)+1),
30142 r0 : 230,
30143 g0 : 230,
30144 b0 : 230
30145 };
30146 } else
30147 color = GeoTemConfig.colors[GeoTemConfig.assignedColorCount];
30148
30149 //make sure that no other dataset has this color
30150 //TODO: one could also check that they are not too much alike
30151 var found = false;
30152 for (var i = 0; i < GeoTemConfig.datasets.length; i++){
30153 var dataset = GeoTemConfig.datasets[i];
30154
30155 if (typeof dataset.color === "undefined")
30156 continue;
30157
30158 if ( (dataset.color.r1 == color.r1) &&
30159 (dataset.color.g1 == color.g1) &&
30160 (dataset.color.b1 == color.b1) ){
30161 found = true;
30162 break;
30163 }
30164 }
30165 if (found === true){
30166 if( GeoTemConfig.colors.length <= GeoTemConfig.assignedColorCount ){
30167 //next time skip over this color
30168 GeoTemConfig.assignedColorCount++;
30169 }
30170 continue;
30171 } else {
30172 GeoTemConfig.colors.push(color);
30173 break;
30174 }
30175 }
30176 GeoTemConfig.datasets[id].color = color;
30177
30178 GeoTemConfig.assignedColorCount++;
30179 }
30180 return GeoTemConfig.datasets[id].color;
30181 };
30182
30183 GeoTemConfig.getAverageDatasetColor = function(id, objects){
30184 var c = new Object();
30185 var datasetColor = GeoTemConfig.getColor(id);
30186 c.r0 = datasetColor.r0;
30187 c.g0 = datasetColor.g0;
30188 c.b0 = datasetColor.b0;
30189 c.r1 = datasetColor.r1;
30190 c.g1 = datasetColor.g1;
30191 c.b1 = datasetColor.b1;
30192 if (!GeoTemConfig.allowCustomColoring)
30193 return c;
30194 if (objects.length == 0)
30195 return c;
30196 var avgColor = new Object();
30197 avgColor.r0 = 0;
30198 avgColor.g0 = 0;
30199 avgColor.b0 = 0;
30200 avgColor.r1 = 0;
30201 avgColor.g1 = 0;
30202 avgColor.b1 = 0;
30203
30204 $(objects).each(function(){
30205 if (this.hasColorInformation){
30206 avgColor.r0 += this.color.r0;
30207 avgColor.g0 += this.color.g0;
30208 avgColor.b0 += this.color.b0;
30209 avgColor.r1 += this.color.r1;
30210 avgColor.g1 += this.color.g1;
30211 avgColor.b1 += this.color.b1;
30212 } else {
30213 avgColor.r0 += datasetColor.r0;
30214 avgColor.g0 += datasetColor.g0;
30215 avgColor.b0 += datasetColor.b0;
30216 avgColor.r1 += datasetColor.r1;
30217 avgColor.g1 += datasetColor.g1;
30218 avgColor.b1 += datasetColor.b1;
30219 }
30220 });
30221
30222 c.r0 = Math.floor(avgColor.r0/objects.length);
30223 c.g0 = Math.floor(avgColor.g0/objects.length);
30224 c.b0 = Math.floor(avgColor.b0/objects.length);
30225 c.r1 = Math.floor(avgColor.r1/objects.length);
30226 c.g1 = Math.floor(avgColor.g1/objects.length);
30227 c.b1 = Math.floor(avgColor.b1/objects.length);
30228
30229 return c;
30230 };
30231
30232 GeoTemConfig.getString = function(field) {
30233 if ( typeof Tooltips[GeoTemConfig.language] == 'undefined') {
30234 GeoTemConfig.language = 'en';
30235 }
30236 return Tooltips[GeoTemConfig.language][field];
30237 }
30238 /**
30239 * returns the actual mouse position
30240 * @param {Event} e the mouseevent
30241 * @return the top and left position on the screen
30242 */
30243 GeoTemConfig.getMousePosition = function(e) {
30244 if (!e) {
30245 e = window.event;
30246 }
30247 var body = (window.document.compatMode && window.document.compatMode == "CSS1Compat") ? window.document.documentElement : window.document.body;
30248 return {
30249 top : e.pageY ? e.pageY : e.clientY,
30250 left : e.pageX ? e.pageX : e.clientX
30251 };
30252 }
30253 /**
30254 * returns the json object of the file from the given url
30255 * @param {String} url the url of the file to load
30256 * @return json object of given file
30257 */
30258 GeoTemConfig.getJson = function(url) {
30259 var data;
30260 $.ajax({
30261 url : url,
30262 async : false,
30263 dataType : 'json',
30264 success : function(json) {
30265 data = json;
30266 }
30267 });
30268 return data;
30269 }
30270
30271 GeoTemConfig.mergeObjects = function(set1, set2) {
30272 var inside = [];
30273 var newSet = [];
30274 for (var i = 0; i < GeoTemConfig.datasets.length; i++){
30275 inside.push([]);
30276 newSet.push([]);
30277 }
30278 for (var i = 0; i < set1.length; i++) {
30279 for (var j = 0; j < set1[i].length; j++) {
30280 inside[i][set1[i][j].index] = true;
30281 newSet[i].push(set1[i][j]);
30282 }
30283 }
30284 for (var i = 0; i < set2.length; i++) {
30285 for (var j = 0; j < set2[i].length; j++) {
30286 if (!inside[i][set2[i][j].index]) {
30287 newSet[i].push(set2[i][j]);
30288 }
30289 }
30290 }
30291 return newSet;
30292 };
30293
30294 GeoTemConfig.datasets = [];
30295
30296 GeoTemConfig.addDataset = function(newDataset){
30297 GeoTemConfig.datasets.push(newDataset);
30298 Publisher.Publish('filterData', GeoTemConfig.datasets, null);
30299 };
30300
30301 GeoTemConfig.addDatasets = function(newDatasets){
30302 $(newDatasets).each(function(){
30303 GeoTemConfig.datasets.push(this);
30304 });
30305 Publisher.Publish('filterData', GeoTemConfig.datasets, null);
30306 };
30307
30308 GeoTemConfig.removeDataset = function(index){
30309 GeoTemConfig.datasets.splice(index,1);
30310 Publisher.Publish('filterData', GeoTemConfig.datasets, null);
30311 };
30312
30313 /**
30314 * converts the csv-file into json-format
30315 *
30316 * @param {String}
30317 * text
30318 */
30319 GeoTemConfig.convertCsv = function(text){
30320 /* convert here from CSV to JSON */
30321 var json = [];
30322 /* define expected csv table headers (first line) */
30323 var expectedHeaders = new Array("Name","Address","Description","Longitude","Latitude","TimeStamp","TimeSpan:begin","TimeSpan:end","weight");
30324 /* convert csv string to array of arrays using ucsv library */
30325 var csvArray = CSV.csvToArray(text);
30326 /* get real used table headers from csv file (first line) */
30327 var usedHeaders = csvArray[0];
30328 /* loop outer array, begin with second line */
30329 for (var i = 1; i < csvArray.length; i++) {
30330 var innerArray = csvArray[i];
30331 var dataObject = new Object();
30332 var tableContent = new Object();
30333 /* exclude lines with no content */
30334 var hasContent = false;
30335 for (var j = 0; j < innerArray.length; j++) {
30336 if (typeof innerArray[j] !== "undefined"){
30337 if (typeof innerArray[j] === "string"){
30338 if (innerArray[j].length > 0)
30339 hasContent = true;
30340 } else {
30341 hasContent = true;
30342 }
30343 }
30344
30345 if (hasContent === true)
30346 break;
30347 }
30348 if (hasContent === false)
30349 continue;
30350 /* loop inner array */
30351 for (var j = 0; j < innerArray.length; j++) {
30352 /* Name */
30353 if (usedHeaders[j] == expectedHeaders[0]) {
30354 dataObject["name"] = ""+innerArray[j];
30355 tableContent["name"] = ""+innerArray[j];
30356 }
30357 /* Address */
30358 else if (usedHeaders[j] == expectedHeaders[1]) {
30359 dataObject["place"] = ""+innerArray[j];
30360 tableContent["place"] = ""+innerArray[j];
30361 }
30362 /* Description */
30363 else if (usedHeaders[j] == expectedHeaders[2]) {
30364 dataObject["description"] = ""+innerArray[j];
30365 tableContent["description"] = ""+innerArray[j];
30366 }
30367 /* TimeStamp */
30368 else if (usedHeaders[j] == expectedHeaders[5]) {
30369 dataObject["time"] = ""+innerArray[j];
30370 }
30371 /* TimeSpan:begin */
30372 else if (usedHeaders[j] == expectedHeaders[6]) {
30373 tableContent["TimeSpan:begin"] = ""+innerArray[j];
30374 }
30375 /* TimeSpan:end */
30376 else if (usedHeaders[j] == expectedHeaders[7]) {
30377 tableContent["TimeSpan:end"] = ""+innerArray[j];
30378 }
30379 /* weight */
30380 else if (usedHeaders[j] == expectedHeaders[7]) {
30381 dataObject["weight"] = ""+innerArray[j];
30382 }
30383 /* Longitude */
30384 else if (usedHeaders[j] == expectedHeaders[3]) {
30385 dataObject["lon"] = parseFloat(innerArray[j]);
30386 }
30387 /* Latitude */
30388 else if (usedHeaders[j] == expectedHeaders[4]) {
30389 dataObject["lat"] = parseFloat(innerArray[j]);
30390 }
30391 else {
30392 var header = new String(usedHeaders[j]);
30393 //remove leading and trailing Whitespace
30394 header = $.trim(header);
30395 tableContent[header] = ""+innerArray[j];
30396 }
30397 }
30398
30399 dataObject["tableContent"] = tableContent;
30400
30401 json.push(dataObject);
30402 }
30403
30404 return json;
30405 };
30406
30407 /**
30408 * returns the xml dom object of the file from the given url
30409 * @param {String} url the url of the file to load
30410 * @return xml dom object of given file
30411 */
30412 GeoTemConfig.getKml = function(url,asyncFunc) {
30413 var data;
30414 var async = false;
30415 if( asyncFunc ){
30416 async = true;
30417 }
30418 $.ajax({
30419 url : url,
30420 async : async,
30421 dataType : 'xml',
30422 success : function(xml) {
30423 if( asyncFunc ){
30424 asyncFunc(xml);
30425 }
30426 else {
30427 data = xml;
30428 }
30429 }
30430 });
30431 if( !async ){
30432 return data;
30433 }
30434 }
30435
30436 /**
30437 * returns an array of all xml dom object of the kmls
30438 * found in the zip file from the given url
30439 *
30440 * can only be used with asyncFunc (because of browser
30441 * constraints regarding arraybuffer)
30442 *
30443 * @param {String} url the url of the file to load
30444 * @return xml dom object of given file
30445 */
30446 GeoTemConfig.getKmz = function(url,asyncFunc) {
30447 var kmlDom = new Array();
30448
30449 var async = true;
30450 if( !asyncFunc ){
30451 //if no asyncFunc is given return an empty array
30452 return kmlDom;
30453 }
30454
30455 //use XMLHttpRequest as "arraybuffer" is not
30456 //supported in jQuery native $.get
30457 var req = new XMLHttpRequest();
30458 req.open("GET",url,async);
30459 req.responseType = "arraybuffer";
30460 req.onload = function() {
30461 var zip = new JSZip();
30462 zip.load(req.response, {base64:false});
30463 var kmlFiles = zip.file(new RegExp("kml$"));
30464
30465 $(kmlFiles).each(function(){
30466 var kml = this;
30467 if (kml.data != null) {
30468 kmlDom.push($.parseXML(kml.data));
30469 }
30470 });
30471
30472 asyncFunc(kmlDom);
30473 };
30474 req.send();
30475 };
30476
30477 /**
30478 * returns the JSON "object"
30479 * from the csv file from the given url
30480 * @param {String} url the url of the file to load
30481 * @return xml dom object of given file
30482 */
30483 GeoTemConfig.getCsv = function(url,asyncFunc) {
30484 var async = false;
30485 if( asyncFunc ){
30486 async = true;
30487 }
30488
30489 //use XMLHttpRequest as synchronous behaviour
30490 //is not supported in jQuery native $.get
30491 var req = new XMLHttpRequest();
30492 req.open("GET",url,async);
30493 //can only be set on asynchronous now
30494 //req.responseType = "text";
30495 var json;
30496 req.onload = function() {
30497 json = GeoTemConfig.convertCsv(req.response);
30498 if( asyncFunc )
30499 asyncFunc(json);
30500 };
30501 req.send();
30502
30503 if( !async ){
30504 return json;
30505 }
30506 };
30507
30508 /**
30509 * returns a Date and a SimileAjax.DateTime granularity value for a given XML time
30510 * @param {String} xmlTime the XML time as String
30511 * @return JSON object with a Date and a SimileAjax.DateTime granularity
30512 */
30513 GeoTemConfig.getTimeData = function(xmlTime) {
30514 if (!xmlTime)
30515 return;
30516 var dateData;
30517 try {
30518 var bc = false;
30519 if (xmlTime.startsWith("-")) {
30520 bc = true;
30521 xmlTime = xmlTime.substring(1);
30522 }
30523 var timeSplit = xmlTime.split("T");
30524 var timeData = timeSplit[0].split("-");
30525 for (var i = 0; i < timeData.length; i++) {
30526 parseInt(timeData[i]);
30527 }
30528 if (bc) {
30529 timeData[0] = "-" + timeData[0];
30530 }
30531 if (timeSplit.length == 1) {
30532 dateData = timeData;
30533 } else {
30534 var dayData;
30535 if (timeSplit[1].indexOf("Z") != -1) {
30536 dayData = timeSplit[1].substring(0, timeSplit[1].indexOf("Z") - 1).split(":");
30537 } else {
30538 dayData = timeSplit[1].substring(0, timeSplit[1].indexOf("+") - 1).split(":");
30539 }
30540 for (var i = 0; i < timeData.length; i++) {
30541 parseInt(dayData[i]);
30542 }
30543 dateData = timeData.concat(dayData);
30544 }
30545 } catch (exception) {
30546 return null;
30547 }
30548 var date, granularity;
30549 if (dateData.length == 6) {
30550 granularity = SimileAjax.DateTime.SECOND;
30551 date = new Date(Date.UTC(dateData[0], dateData[1] - 1, dateData[2], dateData[3], dateData[4], dateData[5]));
30552 } else if (dateData.length == 3) {
30553 granularity = SimileAjax.DateTime.DAY;
30554 date = new Date(Date.UTC(dateData[0], dateData[1] - 1, dateData[2]));
30555 } else if (dateData.length == 2) {
30556 granularity = SimileAjax.DateTime.MONTH;
30557 date = new Date(Date.UTC(dateData[0], dateData[1] - 1, 1));
30558 } else if (dateData.length == 1) {
30559 granularity = SimileAjax.DateTime.YEAR;
30560 date = new Date(Date.UTC(dateData[0], 0, 1));
30561 }
30562 if (timeData[0] && timeData[0] < 100) {
30563 date.setFullYear(timeData[0]);
30564 }
30565
30566 //check data validity;
30567 var isValidDate = true;
30568 if ( date instanceof Date ) {
30569 if ( isNaN( date.getTime() ) )
30570 isValidDate = false;
30571 } else
30572 isValidDate = false;
30573
30574 if (!isValidDate){
30575 if (typeof console !== "undefined")
30576 console.error(xmlTime + " is no valid time format");
30577 return null;
30578 }
30579
30580 return {
30581 date : date,
30582 granularity : granularity
30583 };
30584 }
30585 /**
30586 * converts a JSON array into an array of data objects
30587 * @param {JSON} JSON a JSON array of data items
30588 * @return an array of data objects
30589 */
30590 GeoTemConfig.loadJson = function(JSON) {
30591 var mapTimeObjects = [];
30592 var runningIndex = 0;
30593 for (var i in JSON ) {
30594 try {
30595 var item = JSON[i];
30596 var index = item.index || item.id || runningIndex++;
30597 var name = item.name || "";
30598 var description = item.description || "";
30599 var tableContent = item.tableContent || [];
30600 var locations = [];
30601 if (item.location instanceof Array) {
30602 for (var j = 0; j < item.location.length; j++) {
30603 var place = item.location[j].place || "unknown";
30604 var lon = item.location[j].lon;
30605 var lat = item.location[j].lat;
30606 if ((typeof lon === "undefined" || typeof lat === "undefined" || isNaN(lon) || isNaN(lat) ) && !GeoTemConfig.incompleteData) {
30607 throw "e";
30608 }
30609 locations.push({
30610 longitude : lon,
30611 latitude : lat,
30612 place : place
30613 });
30614 }
30615 } else {
30616 var place = item.place || "unknown";
30617 var lon = item.lon;
30618 var lat = item.lat;
30619 if ((typeof lon === "undefined" || typeof lat === "undefined" || isNaN(lon) || isNaN(lat) ) && !GeoTemConfig.incompleteData) {
30620 throw "e";
30621 }
30622 locations.push({
30623 longitude : lon,
30624 latitude : lat,
30625 place : place
30626 });
30627 }
30628 var dates = [];
30629 if (item.time instanceof Array) {
30630 for (var j = 0; j < item.time.length; j++) {
30631 var time = GeoTemConfig.getTimeData(item.time[j]);
30632 if (time == null && !GeoTemConfig.incompleteData) {
30633 throw "e";
30634 }
30635 dates.push(time);
30636 }
30637 } else {
30638 var time = GeoTemConfig.getTimeData(item.time);
30639 if (time == null && !GeoTemConfig.incompleteData) {
30640 throw "e";
30641 }
30642 if (time != null) {
30643 dates.push(time);
30644 }
30645 }
30646 var weight = item.weight || 1;
30647 //per default GeoTemCo uses WGS84 (-90<=lat<=90, -180<=lon<=180)
30648 var projection = new OpenLayers.Projection("EPSG:4326");
30649 var mapTimeObject = new DataObject(name, description, locations, dates, weight, tableContent, projection);
30650 mapTimeObject.setIndex(index);
30651 mapTimeObjects.push(mapTimeObject);
30652 } catch(e) {
30653 continue;
30654 }
30655 }
30656
30657 if (GeoTemConfig.loadColorFromDataset)
30658 GeoTemConfig.loadDataObjectColoring(mapTimeObjects);
30659
30660 return mapTimeObjects;
30661 }
30662 /**
30663 * converts a KML dom into an array of data objects
30664 * @param {XML dom} kml the XML dom for the KML file
30665 * @return an array of data objects
30666 */
30667 GeoTemConfig.loadKml = function(kml) {
30668 var mapObjects = [];
30669 var elements = kml.getElementsByTagName("Placemark");
30670 if (elements.length == 0) {
30671 return [];
30672 }
30673 var index = 0;
30674 var descriptionTableHeaders = [];
30675 var xmlSerializer = new XMLSerializer();
30676
30677 for (var i = 0; i < elements.length; i++) {
30678 var placemark = elements[i];
30679 var name, description, place, granularity, lon, lat, tableContent = [], time = [], location = [];
30680 var weight = 1;
30681 var timeData = false, mapData = false;
30682
30683 try {
30684 description = placemark.getElementsByTagName("description")[0].childNodes[0].nodeValue;
30685
30686 //cleanWhitespace removes non-sense text-nodes (space, tab)
30687 //and is an addition to jquery defined above
30688 try {
30689 var descriptionDocument = $($.parseXML(description)).cleanWhitespace();
30690
30691 //check whether the description element contains a table
30692 //if yes, this data will be loaded as separate columns
30693 $(descriptionDocument).find("table").each(function(){
30694 $(this).find("tr").each(
30695 function() {
30696 var isHeader = true;
30697 var lastHeader = "";
30698
30699 $(this).find("td").each(
30700 function() {
30701 if (isHeader) {
30702 lastHeader = $.trim($(this).text());
30703 isHeader = false;
30704 } else {
30705 var value = "";
30706
30707 //if this td contains HTML, serialize all
30708 //it's children (the "content"!)
30709 $(this).children().each(
30710 function() {
30711 value += xmlSerializer.serializeToString(this);
30712 }
30713 );
30714
30715 //no HTML content (or no content at all)
30716 if (value.length == 0)
30717 value = $(this).text();
30718 if (typeof value === "undefined")
30719 value = "";
30720
30721 if ($.inArray(lastHeader, descriptionTableHeaders) === -1)
30722 descriptionTableHeaders.push(lastHeader);
30723
30724 if (tableContent[lastHeader] != null)
30725 //append if a field occures more than once
30726 tableContent[lastHeader] += "\n" + value;
30727 else
30728 tableContent[lastHeader] = value;
30729
30730 isHeader = true;
30731 }
30732 }
30733 );
30734 }
30735 );
30736 });
30737 } catch(e) {
30738 //couldn't be parsed, so it contains no html table
30739 //or is not in valid XHTML syntax
30740 }
30741
30742 //check whether the description element contains content in the form of equations
30743 //e.g. someDescriptor = someValue, where these eqations are separated by <br/>
30744 //if yes, this data will be loaded as separate columns
30745 var descriptionRows = description.replace(/<\s*br\s*[\/]*\s*>/g,"<br/>");
30746 $(descriptionRows.split("<br/>")).each(function(){
30747 var row = this;
30748
30749 if (typeof row === "undefined")
30750 return;
30751
30752 var headerAndValue = row.split("=");
30753 if (headerAndValue.length != 2)
30754 return;
30755
30756 var header = $.trim(headerAndValue[0]);
30757 var value = $.trim(headerAndValue[1]);
30758
30759 if ($.inArray(header, descriptionTableHeaders) === -1)
30760 descriptionTableHeaders.push(header);
30761
30762 if (tableContent[header] != null)
30763 //append if a field occures more than once
30764 tableContent[header] += "\n" + value;
30765 else
30766 tableContent[header] = value;
30767 });
30768
30769 tableContent["description"] = description;
30770 } catch(e) {
30771 description = "";
30772 }
30773
30774 try {
30775 name = placemark.getElementsByTagName("name")[0].childNodes[0].nodeValue;
30776 tableContent["name"] = name;
30777 } catch(e) {
30778 if (typeof tableContent["name"] !== "undefined")
30779 name = tableContent["name"];
30780 else
30781 name = "";
30782 }
30783
30784 try {
30785 place = placemark.getElementsByTagName("address")[0].childNodes[0].nodeValue;
30786 tableContent["place"] = place;
30787 } catch(e) {
30788 if (typeof tableContent["place"] !== "undefined")
30789 place = tableContent["place"];
30790 else
30791 place = "";
30792 }
30793
30794 try {
30795 var coordinates = placemark.getElementsByTagName("Point")[0].getElementsByTagName("coordinates")[0].childNodes[0].nodeValue;
30796 var lonlat = coordinates.split(",");
30797 lon = lonlat[0];
30798 lat = lonlat[1];
30799 if (lon == "" || lat == "" || isNaN(lon) || isNaN(lat)) {
30800 throw "e";
30801 }
30802 location.push({
30803 longitude : lon,
30804 latitude : lat,
30805 place : place
30806 });
30807 } catch(e) {
30808 if (!GeoTemConfig.incompleteData) {
30809 continue;
30810 }
30811 }
30812
30813 try {
30814 var tuple = GeoTemConfig.getTimeData(placemark.getElementsByTagName("TimeStamp")[0].getElementsByTagName("when")[0].childNodes[0].nodeValue);
30815 if (tuple != null) {
30816 time.push(tuple);
30817 timeData = true;
30818 } else if (!GeoTemConfig.incompleteData) {
30819 continue;
30820 }
30821 } catch(e) {
30822 try {
30823 if ( (typeof tableContent["TimeSpan:begin"] === "undefined") &&
30824 (typeof tableContent["TimeSpan:end"] === "undefined") ){
30825 var timeStart = $(placemark).find("TimeSpan begin").text();
30826 var timeEnd = $(placemark).find("TimeSpan end").text();
30827
30828 if ( (timeStart != "") && (timeStart != "") ){
30829 tableContent["TimeSpan:begin"] = timeStart;
30830 tableContent["TimeSpan:end"] = timeEnd;
30831
30832 timeData = true;
30833 }
30834 }
30835 } catch(e) {
30836 if (!GeoTemConfig.incompleteData) {
30837 continue;
30838 }
30839 }
30840 }
30841 //per default GeoTemCo uses WGS84 (-90<=lat<=90, -180<=lon<=180)
30842 var projection = new OpenLayers.Projection("EPSG:4326");
30843 var object = new DataObject(name, description, location, time, 1, tableContent, projection);
30844 object.setIndex(index);
30845 index++;
30846 mapObjects.push(object);
30847 }
30848
30849 //make sure that all "description table" columns exists in all rows
30850 if (descriptionTableHeaders.length > 0){
30851 $(mapObjects).each(function(){
30852 var object = this;
30853 $(descriptionTableHeaders).each(function(){
30854 if (typeof object.tableContent[this] === "undefined")
30855 object.tableContent[this] = "";
30856 });
30857 });
30858 }
30859
30860 if (GeoTemConfig.loadColorFromDataset)
30861 GeoTemConfig.loadDataObjectColoring(mapObjects);
30862
30863 return mapObjects;
30864 };
30865
30866 GeoTemConfig.createKMLfromDataset = function(index){
30867 var kmlContent = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><kml xmlns=\"http://www.opengis.net/kml/2.2\"><Document>";
30868
30869 //credits: Anatoly Mironov, http://stackoverflow.com/questions/2573521/how-do-i-output-an-iso-8601-formatted-string-in-javascript
30870 function pad(number) {
30871 var r = String(number);
30872 if ( r.length === 1 ) {
30873 r = '0' + r;
30874 }
30875 return r;
30876 }
30877
30878 var dateToISOString = function(date, granularity) {
30879 var ISOString = date.getFullYear();
30880
30881 if (granularity <= SimileAjax.DateTime.MONTH)
30882 ISOString += '-' + pad( date.getMonth() + 1 );
30883 if (granularity <= SimileAjax.DateTime.DAY)
30884 ISOString += '-' + pad( date.getDate() );
30885 if (granularity <= SimileAjax.DateTime.HOUR){
30886 ISOString += 'T' + pad( date.getHours() );
30887 if (granularity <= SimileAjax.DateTime.MINUTE)
30888 ISOString += ':' + pad( date.getMinutes() );
30889 if (granularity <= SimileAjax.DateTime.SECOND)
30890 ISOString += ':' + pad( date.getSeconds() );
30891 if (granularity <= SimileAjax.DateTime.MILLISECOND)
30892 ISOString += '.' + String( (date.getMilliseconds()/1000).toFixed(3) ).slice( 2, 5 );
30893 ISOString += 'Z';
30894 }
30895
30896 return ISOString;
30897 };
30898
30899 $(GeoTemConfig.datasets[index].objects).each(function(){
30900 var name = this.name;
30901 var description = this.description;
30902 //TODO: allow multiple time/date
30903 var place = this.getPlace(0,0);
30904 var lat = this.getLatitude(0);
30905 var lon = this.getLongitude(0);
30906
30907 var kmlEntry = "<Placemark>";
30908
30909 kmlEntry += "<name><![CDATA[" + name + "]]></name>";
30910 kmlEntry += "<address><![CDATA[" + place + "]]></address>";
30911 kmlEntry += "<description><![CDATA[" + description + "]]></description>";
30912 kmlEntry += "<Point><coordinates>" + lon + "," + lat + "</coordinates></Point>";
30913
30914 if (this.isTemporal){
30915 kmlEntry += "<TimeStamp><when>" + dateToISOString(this.getDate(0), this.getTimeGranularity(0)) + "</when></TimeStamp>";
30916 } else if (this.isFuzzyTemporal){
30917 kmlEntry += "<TimeSpan>"+
30918 "<begin>" + dateToISOString(this.TimeSpanBegin.utc().toDate(), this.TimeSpanBeginGranularity) + "</begin>" +
30919 "<end>" + dateToISOString(this.TimeSpanEnd.utc().toDate(), this.TimeSpanEndGranularity) + "</end>" +
30920 "</TimeSpan>";
30921 }
30922
30923 kmlEntry += "</Placemark>";
30924
30925 kmlContent += kmlEntry;
30926 });
30927
30928 kmlContent += "</Document></kml>";
30929
30930 return(kmlContent);
30931 };
30932
30933 GeoTemConfig.createCSVfromDataset = function(index){
30934 var csvContent = "";
30935 var header = ["name", "description", "weight"];
30936 var tableContent = [];
30937
30938 var firstDataObject = GeoTemConfig.datasets[index].objects[0];
30939
30940 for(var key in firstDataObject.tableContent){
30941 var found = false;
30942 $(header).each(function(index,val){
30943 if (val === key){
30944 found = true;
30945 return false;
30946 }
30947 });
30948 if (found === true)
30949 continue;
30950 else
30951 tableContent.push(key);
30952 }
30953
30954 var isFirst = true;
30955 $(header).each(function(key,val){
30956 if (isFirst){
30957 isFirst = false;
30958 } else {
30959 csvContent += ",";
30960 }
30961
30962 //Rename according to CSV import definition
30963 if (val === "name")
30964 val = "Name";
30965 else if (val === "description")
30966 val = "Description";
30967 csvContent += "\""+val+"\"";
30968 });
30969 $(tableContent).each(function(key,val){
30970 if (isFirst){
30971 isFirst = false;
30972 } else {
30973 csvContent += ",";
30974 }
30975 csvContent += "\""+val+"\"";
30976 });
30977 //Names according to CSV import definition
30978 csvContent += ",\"Address\",\"Latitude\",\"Longitude\",\"TimeStamp\"";
30979 csvContent += "\n";
30980
30981 var isFirstRow = true;
30982 $(GeoTemConfig.datasets[index].objects).each(function(){
30983 var elem = this;
30984
30985 if (isFirstRow){
30986 isFirstRow = false;
30987 } else {
30988 csvContent += "\n";
30989 }
30990
30991 var isFirst = true;
30992 $(header).each(function(key,val){
30993 if (isFirst){
30994 isFirst = false;
30995 } else {
30996 csvContent += ",";
30997 }
30998 csvContent += "\""+elem[val]+"\"";
30999 });
31000 $(tableContent).each(function(key,val){
31001 if (isFirst){
31002 isFirst = false;
31003 } else {
31004 csvContent += ",";
31005 }
31006 csvContent += "\""+elem.tableContent[val]+"\"";
31007 });
31008
31009 csvContent += ",";
31010 csvContent += "\"";
31011 if (elem.isGeospatial){
31012 csvContent += elem.locations[0].place;
31013 }
31014 csvContent += "\"";
31015
31016 csvContent += ",";
31017 csvContent += "\"";
31018 if ( (elem.isGeospatial) && (typeof elem.getLatitude(0) !== "undefined") ){
31019 csvContent += elem.getLatitude(0);
31020 }
31021 csvContent += "\"";
31022
31023 csvContent += ",";
31024 csvContent += "\"";
31025 if ( (elem.isGeospatial) && (typeof elem.getLongitude(0) !== "undefined") ){
31026 csvContent += elem.getLongitude(0);
31027 }
31028 csvContent += "\"";
31029
31030 csvContent += ",";
31031 csvContent += "\"";
31032 if ( (elem.isTemporal) && (typeof elem.getDate(0) !== "undefined") ){
31033 //TODO: not supported in IE8 switch to moment.js
31034 csvContent += elem.getDate(0).toISOString();
31035 }
31036 csvContent += "\"";
31037 });
31038
31039 return(csvContent);
31040 };
31041 /**
31042 * iterates over Datasets/DataObjects and loads color values
31043 * from the "color0" and "color1" elements, which contains RGB
31044 * values in hex (CSS style #RRGGBB)
31045 * @param {dataObjects} array of DataObjects
31046 */
31047 GeoTemConfig.loadDataObjectColoring = function(dataObjects) {
31048 $(dataObjects).each(function(){
31049 var r0,g0,b0,r1,g1,b1;
31050 if ( (typeof this.tableContent !== "undefined") &&
31051 (typeof this.tableContent["color0"] !== "undefined") ){
31052 var color = this.tableContent["color0"];
31053 if ( (color.indexOf("#") == 0) && (color.length == 7) ){
31054 r0 = parseInt("0x"+color.substr(1,2));
31055 g0 = parseInt("0x"+color.substr(3,2));
31056 b0 = parseInt("0x"+color.substr(5,2));
31057 }
31058 }
31059 if ( (typeof this.tableContent !== "undefined") &&
31060 (typeof this.tableContent["color1"] !== "undefined") ){
31061 var color = this.tableContent["color1"];
31062 if ( (color.indexOf("#") == 0) && (color.length == 7) ){
31063 r1 = parseInt("0x"+color.substr(1,2));
31064 g1 = parseInt("0x"+color.substr(3,2));
31065 b1 = parseInt("0x"+color.substr(5,2));
31066 }
31067 }
31068
31069 if ( (typeof r0 !== "undefined") && (typeof g0 !== "undefined") && (typeof b0 !== "undefined") &&
31070 (typeof r1 !== "undefined") && (typeof g1 !== "undefined") && (typeof b1 !== "undefined") ){
31071 this.setColor(r0,g0,b0,r1,g1,b1);
31072 delete this.tableContent["color0"];
31073 delete this.tableContent["color1"];
31074 } else {
31075 if (typeof console !== undefined)
31076 console.error("Object '" + this.name + "' has invalid color information");
31077 }
31078 });
31079 };
31080 /*
31081 * MapControl.js
31082 *
31083 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
31084 *
31085 * This library is free software; you can redistribute it and/or
31086 * modify it under the terms of the GNU Lesser General Public
31087 * License as published by the Free Software Foundation; either
31088 * version 3 of the License, or (at your option) any later version.
31089 *
31090 * This library is distributed in the hope that it will be useful,
31091 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31092 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31093 * Lesser General Public License for more details.
31094 *
31095 * You should have received a copy of the GNU Lesser General Public
31096 * License along with this library; if not, write to the Free Software
31097 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31098 * MA 02110-1301 USA
31099 */
31100
31101 /**
31102 * @class MapControl
31103 * Generic map control interface
31104 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
31105 * @release 1.0
31106 * @release date: 2012-07-27
31107 * @version date: 2012-07-27
31108 */
31109 function MapControl(map, button, label, onActivate, onDeactivate) {
31110
31111 var control = this;
31112 this.button = button;
31113 this.enabled = true;
31114 this.activated = false;
31115 this.label = label;
31116
31117 if (this.button != null) {
31118 $(this.button).addClass(label + 'Deactivated');
31119 $(this.button).attr("title", GeoTemConfig.getString(GeoTemConfig.language, label));
31120 //vhz
31121 $(this.button).click(function() {
31122 control.checkStatus();
31123 });
31124 }
31125
31126 this.checkStatus = function() {
31127 if (control.enabled) {
31128 if ( typeof map.activeControl != 'undefined') {
31129 if (control.activated) {
31130 control.deactivate();
31131 } else {
31132 map.activeControl.deactivate();
31133 control.activate();
31134 }
31135 } else {
31136 control.activate();
31137 }
31138 }
31139 };
31140
31141 this.setButtonClass = function(removeClass, addClass) {
31142 if (this.button != null) {
31143 $(this.button).removeClass(label + removeClass);
31144 $(this.button).addClass(label + addClass);
31145 $(this.button).attr("title", GeoTemConfig.getString(GeoTemConfig.language, label));
31146 }
31147 };
31148
31149 this.disable = function() {
31150 this.enabled = false;
31151 this.setButtonClass('Deactivated', 'Disabled');
31152 };
31153
31154 this.enable = function() {
31155 this.enabled = true;
31156 this.setButtonClass('Disabled', 'Deactivated');
31157 };
31158
31159 this.activate = function() {
31160 onActivate();
31161 this.activated = true;
31162 this.setButtonClass('Deactivated', 'Activated');
31163 map.activeControl = this;
31164 };
31165
31166 this.deactivate = function() {
31167 onDeactivate();
31168 this.activated = false;
31169 this.setButtonClass('Activated', 'Deactivated');
31170 map.activeControl = undefined;
31171 };
31172
31173 };
31174 /*
31175 * CircleObject.js
31176 *
31177 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
31178 *
31179 * This library is free software; you can redistribute it and/or
31180 * modify it under the terms of the GNU Lesser General Public
31181 * License as published by the Free Software Foundation; either
31182 * version 3 of the License, or (at your option) any later version.
31183 *
31184 * This library is distributed in the hope that it will be useful,
31185 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31186 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31187 * Lesser General Public License for more details.
31188 *
31189 * You should have received a copy of the GNU Lesser General Public
31190 * License along with this library; if not, write to the Free Software
31191 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31192 * MA 02110-1301 USA
31193 */
31194
31195 /**
31196 * @class CircleObject
31197 * circle object aggregate for the map
31198 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
31199 * @release 1.0
31200 * @release date: 2012-07-27
31201 * @version date: 2012-07-27
31202 *
31203 * @param {float} x the x (longitude) value for the circle
31204 * @param {float} y the y (latitude) value for the circle
31205 * @param {DataObject[]} elements array of data objects belonging to the circle
31206 * @param {float} radius the resulting radius (in pixel) for the circle
31207 * @param {int} search dataset index
31208 * @param {int} weight summed weight of all elements
31209 * @param {JSON} fatherBin bin of the circle object if its part of a circle pack
31210 */
31211 CircleObject = function(originX, originY, shiftX, shiftY, elements, radius, search, weight, fatherBin) {
31212
31213 this.originX = originX;
31214 this.originY = originY;
31215 this.shiftX = shiftX;
31216 this.shiftY = shiftY;
31217 this.elements = elements;
31218 this.radius = radius;
31219 this.search = search;
31220 this.weight = weight;
31221 this.overlay = 0;
31222 this.overlayElements = [];
31223 this.smoothness = 0;
31224 this.fatherBin = fatherBin;
31225
31226 this.feature
31227 this.olFeature
31228 this.percentage = 0;
31229 this.selected = false;
31230
31231 };
31232
31233 CircleObject.prototype = {
31234
31235 /**
31236 * sets the OpenLayers point feature for this point object
31237 * @param {OpenLayers.Feature} pointFeature the point feature for this object
31238 */
31239 setFeature : function(feature) {
31240 this.feature = feature;
31241 },
31242
31243 /**
31244 * sets the OpenLayers point feature for this point object to manage its selection status
31245 * @param {OpenLayers.Feature} olPointFeature the overlay point feature for this object
31246 */
31247 setOlFeature : function(olFeature) {
31248 this.olFeature = olFeature;
31249 },
31250
31251 reset : function() {
31252 this.overlay = 0;
31253 this.overlayElements = [];
31254 this.smoothness = 0;
31255 },
31256
31257 setSelection : function(s) {
31258 this.selected = s;
31259 },
31260
31261 toggleSelection : function() {
31262 this.selected = !this.selected;
31263 }
31264 };
31265 /*
31266 * FilterBar.js
31267 *
31268 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
31269 *
31270 * This library is free software; you can redistribute it and/or
31271 * modify it under the terms of the GNU Lesser General Public
31272 * License as published by the Free Software Foundation; either
31273 * version 3 of the License, or (at your option) any later version.
31274 *
31275 * This library is distributed in the hope that it will be useful,
31276 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31277 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31278 * Lesser General Public License for more details.
31279 *
31280 * You should have received a copy of the GNU Lesser General Public
31281 * License along with this library; if not, write to the Free Software
31282 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31283 * MA 02110-1301 USA
31284 */
31285
31286 /**
31287 * @class FilterBar
31288 * Implementation for FilterBar Object
31289 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
31290 * @release 1.0
31291 * @release date: 2012-07-27
31292 * @version date: 2012-07-27
31293 *
31294 * @param {Object} parent parent to call filter functions
31295 * @param {HTML object} parentDiv div to append filter buttons
31296 */
31297 function FilterBar(parent, parentDiv) {
31298
31299 var bar = this;
31300
31301 this.filter = document.createElement('div');
31302 this.filter.setAttribute('class', 'smallButton filterDisabled');
31303 this.filter.onclick = function() {
31304 parent.filtering();
31305 };
31306
31307 this.filterInverse = document.createElement('div');
31308 this.filterInverse.setAttribute('class', 'smallButton filterInverseDisabled');
31309 this.filterInverse.onclick = function() {
31310 parent.inverseFiltering();
31311 };
31312 if (!GeoTemConfig.inverseFilter) {
31313 this.filterInverse.style.display = 'none';
31314 }
31315
31316 this.cancelSelection = document.createElement('div');
31317 this.cancelSelection.setAttribute('class', 'smallButton filterCancelDisabled');
31318 this.cancelSelection.onclick = function() {
31319 parent.deselection();
31320 };
31321
31322 this.appendTo = function(parentDiv) {
31323 parentDiv.appendChild(this.filter);
31324 parentDiv.appendChild(this.filterInverse);
31325 parentDiv.appendChild(this.cancelSelection);
31326 }
31327 if ( typeof parentDiv != 'undefined') {
31328 this.appendTo(parentDiv);
31329 }
31330
31331 this.reset = function(show) {
31332 if (show) {
31333 this.filter.setAttribute('class', 'smallButton filter');
31334 this.filterInverse.setAttribute('class', 'smallButton filterInverse');
31335 this.cancelSelection.setAttribute('class', 'smallButton filterCancel');
31336 } else {
31337 this.filter.setAttribute('class', 'smallButton filterDisabled');
31338 this.filterInverse.setAttribute('class', 'smallButton filterInverseDisabled');
31339 this.cancelSelection.setAttribute('class', 'smallButton filterCancelDisabled');
31340 }
31341 };
31342
31343 };
31344 /*
31345 * Selection.js
31346 *
31347 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
31348 *
31349 * This library is free software; you can redistribute it and/or
31350 * modify it under the terms of the GNU Lesser General Public
31351 * License as published by the Free Software Foundation; either
31352 * version 3 of the License, or (at your option) any later version.
31353 *
31354 * This library is distributed in the hope that it will be useful,
31355 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31356 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31357 * Lesser General Public License for more details.
31358 *
31359 * You should have received a copy of the GNU Lesser General Public
31360 * License along with this library; if not, write to the Free Software
31361 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31362 * MA 02110-1301 USA
31363 */
31364
31365 /**
31366 * @class Selection
31367 * Selection Class
31368 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
31369 * @release 1.0
31370 * @release date: 2012-07-27
31371 * @version date: 2012-07-27
31372 *
31373 * @param {Array} objects array of selected objects
31374 * @param {Object} widget which belongs to selection
31375 */
31376 function Selection(objects, widget) {
31377
31378 this.objects = objects;
31379 if ( typeof objects == 'undefined') {
31380 this.objects = [];
31381 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
31382 this.objects.push([]);
31383 }
31384 }
31385 this.widget = widget;
31386
31387 this.getObjects = function(widget) {
31388 if (!this.equal(widget)) {
31389 return this.objects;
31390 }
31391 this.objects = [];
31392 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
31393 this.objects.push([]);
31394 }
31395 return this.objects;
31396 };
31397
31398 this.equal = function(widget) {
31399 if (this.valid() && this.widget != widget) {
31400 return false;
31401 }
31402 return true;
31403 };
31404
31405 this.valid = function() {
31406 if ( typeof this.widget != 'undefined') {
31407 return true;
31408 }
31409 return false;
31410 };
31411
31412 this.loadAllObjects = function() {
31413 allObjects = [];
31414 $(GeoTemConfig.datasets).each(function(){
31415 var singleDatasetObjects = [];
31416 $(this.objects).each(function(){
31417 singleDatasetObjects.push(this);
31418 });
31419 allObjects.push(singleDatasetObjects);
31420 });
31421 this.objects = allObjects;
31422 };
31423 };
31424
31425 /*
31426 * PlacenameTags.js
31427 *
31428 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
31429 *
31430 * This library is free software; you can redistribute it and/or
31431 * modify it under the terms of the GNU Lesser General Public
31432 * License as published by the Free Software Foundation; either
31433 * version 3 of the License, or (at your option) any later version.
31434 *
31435 * This library is distributed in the hope that it will be useful,
31436 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31437 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
31438 * Lesser General Public License for more details.
31439 *
31440 * You should have received a copy of the GNU Lesser General Public
31441 * License along with this library; if not, write to the Free Software
31442 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31443 * MA 02110-1301 USA
31444 */
31445
31446 /**
31447 * @class PlacenameTags
31448 * place labels computation for circles
31449 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
31450 * @release 1.0
31451 * @release date: 2012-07-27
31452 * @version date: 2012-07-27
31453 */
31454 function PlacenameTags(circle, map) {
31455
31456 this.circle = circle;
31457 this.map = map;
31458
31459 this.placeLabels
31460 this.selectedLabel
31461
31462 this.allLabel
31463 this.othersLabel
31464 this.unknownLabel
31465
31466 this.calculate = function() {
31467 this.calculateLabels();
31468 this.calculatePlacenameTags();
31469 }
31470
31471 this.calculateLabels = function() {
31472 var elements = this.circle.elements;
31473 var k = this.circle.search;
31474 var weight = 0;
31475 var labels = [];
31476
31477 var levelOfDetail = 0;
31478 if (this.map.options.placenameTagsStyle === 'zoom')
31479 levelOfDetail = this.map.getLevelOfDetail();
31480
31481 if (this.map.options.placenameTagsStyle === 'value'){
31482 //find max level that _all_ elements have a value for
31483 var maxLevel;
31484 for (var i = 0; i < elements.length; i++) {
31485 var level = elements[i].placeDetails[this.map.options.mapIndex].length-1;
31486
31487 if (typeof maxLevel === "undefined")
31488 maxLevel = level;
31489 if (maxLevel > level)
31490 maxLevel = level;
31491 //smallest level anyway, no need to look any further
31492 if (level == 0)
31493 break;
31494 }
31495 //search for highest level where the values differ
31496 for (levelOfDetail = 0; levelOfDetail < maxLevel; levelOfDetail++){
31497 var differenceFound = false;
31498 for (var i = 0; i < (elements.length-1); i++) {
31499 if ( elements[i].getPlace(this.map.options.mapIndex, levelOfDetail) !==
31500 elements[i+1].getPlace(this.map.options.mapIndex, levelOfDetail))
31501 differenceFound = true;
31502 }
31503 if (differenceFound === true)
31504 break;
31505 }
31506 }
31507
31508 for (var i = 0; i < elements.length; i++) {
31509 weight += elements[i].weight;
31510 var found = false;
31511 var label = elements[i].getPlace(this.map.options.mapIndex, levelOfDetail);
31512 if (label == "") {
31513 label = "unknown";
31514 }
31515 for (var j = 0; j < labels.length; j++) {
31516 if (labels[j].place == label) {
31517 labels[j].elements.push(elements[i]);
31518 labels[j].weight += elements[i].weight;
31519 found = true;
31520 break;
31521 }
31522 }
31523 if (!found) {
31524 labels.push({
31525 id : elements[i].name,
31526 place : label,
31527 elements : new Array(elements[i]),
31528 weight : elements[i].weight,
31529 index : k
31530 });
31531 }
31532 }
31533 var sortBySize = function(label1, label2) {
31534 if (label1.weight > label2.weight) {
31535 return -1;
31536 }
31537 return 1;
31538 }
31539 labels.sort(sortBySize);
31540 if (map.options.maxPlaceLabels) {
31541 var ml = map.options.maxPlaceLabels;
31542 if (ml == 1) {
31543 labels = [];
31544 labels.push({
31545 place : "all",
31546 elements : elements,
31547 weight : weight,
31548 index : k
31549 });
31550 }
31551 if (ml == 2) {
31552 ml++;
31553 }
31554 if (ml > 2 && labels.length + 1 > ml) {
31555 var c = [];
31556 var w = 0;
31557 for (var i = ml - 2; i < labels.length; i++) {
31558 c = c.concat(labels[i].elements);
31559 w += labels[i].weight;
31560 }
31561 labels = labels.slice(0, ml - 2);
31562 labels.push({
31563 place : "others",
31564 elements : c,
31565 weight : w,
31566 index : k
31567 });
31568 }
31569 }
31570 if (labels.length > 1) {
31571 labels.push({
31572 place : "all",
31573 elements : elements,
31574 weight : weight,
31575 index : k
31576 });
31577 }
31578 this.placeLabels = labels;
31579 };
31580
31581 this.calculatePlacenameTags = function() {
31582 var cloud = this;
31583 var c = GeoTemConfig.getColor(this.circle.search);
31584 if( map.options.useGraphics ){
31585 c = map.config.getGraphic(this.circle.search).color;
31586 }
31587 var color0 = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
31588 var color1 = 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')';
31589 var allStyles = "", hoverStyle = "", highlightStyle = "", selectedStyle = "", unselectedStyle = "";
31590
31591 if (GeoTemConfig.ie) {
31592 highlightStyle += map.options.ieHighlightLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31593 hoverStyle += map.options.ieHoveredLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31594 selectedStyle += map.options.ieSelectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31595 unselectedStyle += map.options.ieUnselectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31596 } else {
31597 highlightStyle += map.options.highlightLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31598 hoverStyle += map.options.hoveredLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31599 selectedStyle += map.options.selectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31600 unselectedStyle += map.options.unselectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31601 }
31602
31603 var clickFunction = function(label) {
31604 label.div.onclick = function() {
31605 cloud.changeLabelSelection(label);
31606 }
31607 }
31608 var maxLabelSize = this.count
31609 for (var i = 0; i < this.placeLabels.length; i++) {
31610 var l = this.placeLabels[i];
31611 l.selected = false;
31612 var div = document.createElement("div");
31613 div.setAttribute('class', 'tagCloudItem');
31614 var fontSize = 1 + (l.weight - 1) / this.map.count * map.options.maxLabelIncrease;
31615 if (l.place == "all") {
31616 fontSize = 1;
31617 }
31618 div.style.fontSize = fontSize + "em";
31619 l.allStyle = allStyles + "font-size: " + fontSize + "em;";
31620 l.selectedStyle = selectedStyle;
31621 l.unselectedStyle = unselectedStyle;
31622 l.highlightStyle = highlightStyle;
31623 l.hoverStyle = hoverStyle;
31624 div.innerHTML = l.place + "<span style='font-size:" + (1 / fontSize) + "em'>&nbsp;(" + l.weight + ")</span>";
31625 l.div = div;
31626 clickFunction(l);
31627 }
31628 if (map.options.labelGrid) {
31629 this.showPlacelabels();
31630 } else {
31631 for (var i = 0; i < this.placeLabels.length; i++) {
31632 this.placeLabels[i].div.setAttribute('style', this.placeLabels[i].allStyle + "" + this.placeLabels[i].highlightStyle);
31633 }
31634 }
31635 };
31636
31637 this.selectLabel = function(label) {
31638 if ( typeof label == 'undefined') {
31639 label = this.placeLabels[this.placeLabels.length - 1];
31640 }
31641 if (this.map.popup) {
31642 this.map.popup.showLabelContent(label);
31643 }
31644 this.selectedLabel = label;
31645 this.selectedLabel.div.setAttribute('style', this.selectedLabel.allStyle + "" + this.selectedLabel.selectedStyle);
31646 this.map.mapLabelSelection(label);
31647 };
31648
31649 // changes selection between labels (click, hover)
31650 this.changeLabelSelection = function(label) {
31651 if (this.selectedLabel == label) {
31652 return;
31653 }
31654 if ( typeof this.selectedLabel != 'undefined') {
31655 this.selectedLabel.div.setAttribute('style', this.selectedLabel.allStyle + "" + this.selectedLabel.unselectedStyle);
31656 }
31657 this.selectLabel(label);
31658 };
31659
31660 this.showPlacelabels = function() {
31661 this.leftDiv = document.createElement("div");
31662 this.leftDiv.setAttribute('class', 'tagCloudDiv');
31663 this.map.gui.mapWindow.appendChild(this.leftDiv);
31664 this.rightDiv = document.createElement("div");
31665 this.rightDiv.setAttribute('class', 'tagCloudDiv');
31666 this.map.gui.mapWindow.appendChild(this.rightDiv);
31667 for (var i = 0; i < this.placeLabels.length; i++) {
31668 if (i % 2 == 0) {
31669 this.leftDiv.appendChild(this.placeLabels[i].div);
31670 } else {
31671 this.rightDiv.appendChild(this.placeLabels[i].div);
31672 }
31673 this.placeLabels[i].div.setAttribute('style', this.placeLabels[i].allStyle + "" + this.placeLabels[i].highlightStyle);
31674 }
31675 this.placeTagCloud();
31676 };
31677
31678 this.placeTagCloud = function() {
31679 var lonlat = new OpenLayers.LonLat(this.circle.feature.geometry.x, this.circle.feature.geometry.y);
31680 var pixel = map.openlayersMap.getPixelFromLonLat(lonlat);
31681 var radius = this.circle.feature.style.pointRadius;
31682 var lw = this.leftDiv.offsetWidth;
31683 var rw = this.rightDiv.offsetWidth;
31684 this.leftDiv.style.left = (pixel.x - radius - lw - 5) + "px";
31685 this.rightDiv.style.left = (pixel.x + radius + 5) + "px";
31686 var lh = this.leftDiv.offsetHeight;
31687 var rh = this.rightDiv.offsetHeight;
31688 var lt = pixel.y - lh / 2;
31689 var rt = pixel.y - rh / 2;
31690 this.leftDiv.style.top = lt + "px";
31691 this.rightDiv.style.top = rt + "px";
31692 };
31693
31694 this.remove = function() {
31695 $(this.leftDiv).remove();
31696 $(this.rightDiv).remove();
31697 };
31698
31699 };
31700
31701 function PackPlacenameTags(circle, map) {
31702
31703 this.circle = circle;
31704 this.map = map;
31705
31706 this.placeLabels
31707 this.selectedLabel
31708
31709 this.allLabel
31710 this.othersLabel
31711 this.unknownLabel
31712
31713 this.calculate = function() {
31714 this.calculateLabels();
31715 this.calculatePlacenameTags();
31716 }
31717
31718 this.getLabelList = function(circle) {
31719
31720 var elements = circle.elements;
31721 var k = circle.search;
31722 var weight = 0;
31723 var labels = [];
31724 var levelOfDetail = this.map.getLevelOfDetail();
31725 for (var i = 0; i < elements.length; i++) {
31726 weight += elements[i].weight;
31727 var found = false;
31728 var label = elements[i].getPlace(this.map.options.mapIndex, levelOfDetail);
31729 if (label == "") {
31730 label = "unknown";
31731 }
31732 for (var j = 0; j < labels.length; j++) {
31733 if (labels[j].place == label) {
31734 labels[j].elements.push(elements[i]);
31735 labels[j].weight += elements[i].weight;
31736 found = true;
31737 break;
31738 }
31739 }
31740 if (!found) {
31741 labels.push({
31742 id : elements[i].name,
31743 place : label,
31744 elements : new Array(elements[i]),
31745 weight : elements[i].weight,
31746 index : k
31747 });
31748 }
31749 }
31750 var sortBySize = function(label1, label2) {
31751 if (label1.weight > label2.weight) {
31752 return -1;
31753 }
31754 return 1;
31755 }
31756 labels.sort(sortBySize);
31757 var droppedLabels = [];
31758 if (map.options.maxPlaceLabels) {
31759 var ml = map.options.maxPlaceLabels;
31760 if (ml == 1) {
31761 labels = [];
31762 labels.push({
31763 place : "all",
31764 elements : elements,
31765 weight : weight,
31766 index : k
31767 });
31768 }
31769 if (ml == 2) {
31770 ml++;
31771 }
31772 if (ml > 2 && labels.length + 1 > ml) {
31773 var c = [];
31774 var w = 0;
31775 for (var i = ml - 2; i < labels.length; i++) {
31776 c = c.concat(labels[i].elements);
31777 w += labels[i].weight;
31778 droppedLabels.push(labels[i]);
31779 }
31780 labels = labels.slice(0, ml - 2);
31781 var ol = {
31782 place : "others",
31783 elements : c,
31784 weight : w,
31785 index : k
31786 };
31787 labels.push(ol);
31788 this.othersLabels.push(ol);
31789 }
31790 }
31791 if (labels.length > 1) {
31792 labels.push({
31793 place : "all",
31794 elements : elements,
31795 weight : weight,
31796 index : k
31797 });
31798 }
31799 this.placeLabels.push(labels);
31800 this.droppedLabels.push(droppedLabels);
31801 };
31802
31803 this.calculateLabels = function() {
31804 var circles = this.circle.circles;
31805 this.placeLabels = [];
31806 this.droppedLabels = [];
31807 this.othersLabels = [];
31808 for (var i = 0; i < circles.length; i++) {
31809 this.getLabelList(circles[i]);
31810 }
31811 };
31812
31813 this.calculatePlacenameTags = function() {
31814 var cloud = this;
31815
31816 var unselectedStyles = [];
31817 var selectedStyles = [];
31818 var hoverStyles = [];
31819
31820 for (var k = 0; k < this.placeLabels.length; k++) {
31821 var c = GeoTemConfig.getColor(this.circle.circles[k].search);
31822 if( map.options.useGraphics ){
31823 c = map.config.getGraphic(this.circle.circles[k].search).color;
31824 }
31825 var color0 = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
31826 var color1 = 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')';
31827 var allStyles = "", hoverStyle = "", highlightStyle = "", selectedStyle = "", unselectedStyle = "";
31828
31829 if (GeoTemConfig.ie) {
31830 highlightStyle += map.options.ieHighlightLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31831 hoverStyle += map.options.ieHoveredLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31832 selectedStyle += map.options.ieSelectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31833 unselectedStyle += map.options.ieUnselectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31834 } else {
31835 highlightStyle += map.options.highlightLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31836 hoverStyle += map.options.hoveredLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31837 selectedStyle += map.options.selectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31838 unselectedStyle += map.options.unselectedLabel.replace(/COLOR1/g, color1).replace(/COLOR0/g, color0) + ";";
31839 }
31840
31841 allStyles += 'margin-right:5px;';
31842 allStyles += 'margin-left:5px;';
31843 unselectedStyles.push(unselectedStyle);
31844 selectedStyles.push(selectedStyle);
31845 hoverStyles.push(hoverStyle);
31846
31847 var clickFunction = function(label, id) {
31848 label.div.onmouseover = function() {
31849 if (!label.opposite) {
31850 var oppositeLabel, oppositeLabelDiv;
31851 label.div.setAttribute('style', allStyles + "" + selectedStyles[id]);
31852 var c = GeoTemConfig.getColor(id);
31853 if( map.options.useGraphics ){
31854 c = map.config.getGraphic(id).color;
31855 }
31856 var color0 = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
31857 if (id == 0) {
31858 for (var i = 0; i < cloud.droppedLabels[1].length; i++) {
31859 if (cloud.droppedLabels[1][i].place == label.place) {
31860 oppositeLabel = cloud.droppedLabels[1][i];
31861 cloud.rightDiv.appendChild(oppositeLabel.div);
31862 cloud.drawLine(cloud.ctxOl, label.div, oppositeLabel.div);
31863 var olDiv = cloud.othersLabels[1].div;
31864 olDiv.innerHTML = olDiv.innerHTML.replace(/\(\d*\)/g, '(' + (cloud.othersLabels[1].weight - oppositeLabel.weight) + ')');
31865 break;
31866 }
31867 }
31868 } else {
31869 for (var i = 0; i < cloud.droppedLabels[0].length; i++) {
31870 if (cloud.droppedLabels[0][i].place == label.place) {
31871 oppositeLabel = cloud.droppedLabels[0][i];
31872 cloud.leftDiv.appendChild(oppositeLabel.div);
31873 cloud.drawLine(cloud.ctxOl, oppositeLabel.div, label.div);
31874 var olDiv = cloud.othersLabels[0].div;
31875 olDiv.innerHTML = olDiv.innerHTML.replace(/\(\d*\)/g, '(' + (cloud.othersLabels[0].weight - oppositeLabel.weight) + ')');
31876 break;
31877 }
31878 }
31879 }
31880 if ( typeof oppositeLabel == 'undefined') {
31881 oppositeLabel = {
31882 div : cloud.naDiv
31883 };
31884 if (id == 0) {
31885 cloud.rightDiv.appendChild(cloud.naDiv);
31886 cloud.drawLine(cloud.ctxOl, label.div, cloud.naDiv);
31887 oppositeLabel.div.setAttribute('style', allStyles + "" + selectedStyles[1]);
31888 } else {
31889 cloud.leftDiv.appendChild(cloud.naDiv);
31890 cloud.drawLine(cloud.ctxOl, cloud.naDiv, label.div);
31891 oppositeLabel.div.setAttribute('style', allStyles + "" + selectedStyles[0]);
31892 }
31893 cloud.map.mapLabelHighlight(label);
31894 } else {
31895 cloud.map.mapLabelHighlight([label, oppositeLabel]);
31896 }
31897 label.div.onmouseout = function() {
31898 label.div.setAttribute('style', allStyles + "" + unselectedStyles[id]);
31899 var olDiv = cloud.othersLabels[0].div;
31900 olDiv.innerHTML = olDiv.innerHTML.replace(/\(\d*\)/g, '(' + cloud.othersLabels[0].weight + ')');
31901 var olDiv2 = cloud.othersLabels[1].div;
31902 olDiv2.innerHTML = olDiv2.innerHTML.replace(/\(\d*\)/g, '(' + cloud.othersLabels[1].weight + ')');
31903 $(oppositeLabel.div).remove();
31904 cloud.ctxOl.clearRect(0, 0, cloud.cvOl.width, cloud.cvOl.height);
31905 cloud.map.mapLabelHighlight();
31906 }
31907 }
31908 }
31909 }
31910 var maxLabelSize = this.count
31911 for (var i = 0; i < this.placeLabels[k].length; i++) {
31912 var l = this.placeLabels[k][i];
31913 l.selected = false;
31914 var div = document.createElement("div");
31915 div.setAttribute('class', 'tagCloudItem');
31916 var fontSize = 1 + (l.weight - 1) / this.map.count * map.options.maxLabelIncrease;
31917 if (l.place == "all") {
31918 fontSize = 1;
31919 }
31920 div.style.fontSize = fontSize + "em";
31921 l.allStyle = allStyles + "font-size: " + fontSize + "em;";
31922 l.selectedStyle = selectedStyle;
31923 l.unselectedStyle = unselectedStyle;
31924 l.hoverStyle = hoverStyle;
31925 div.innerHTML = l.place + "<span style='font-size:" + (1 / fontSize) + "em'>&nbsp;(" + l.weight + ")</span>";
31926 l.div = div;
31927 clickFunction(l, k);
31928 }
31929 for (var i = 0; i < this.droppedLabels[k].length; i++) {
31930 var l = this.droppedLabels[k][i];
31931 l.selected = false;
31932 var div = document.createElement("div");
31933 div.setAttribute('class', 'tagCloudItem');
31934 var fontSize = 1 + (l.weight - 1) / this.map.count * map.options.maxLabelIncrease;
31935 div.style.fontSize = fontSize + "em";
31936 l.allStyle = allStyles + "font-size: " + fontSize + "em;";
31937 l.selectedStyle = selectedStyle;
31938 l.unselectedStyle = unselectedStyle;
31939 l.hoverStyle = hoverStyle;
31940 div.innerHTML = l.place + "<span style='font-size:" + (1 / fontSize) + "em'>&nbsp;(" + l.weight + ")</span>";
31941 l.div = div;
31942 div.setAttribute('style', allStyles + "" + selectedStyle);
31943 }
31944 }
31945
31946 this.naDiv = document.createElement("div");
31947 this.naDiv.setAttribute('class', 'tagCloudItem');
31948 var fontSize = 1;
31949 div.style.fontSize = fontSize + "em";
31950 l.allStyle = allStyles + "font-size: " + fontSize + "em;";
31951 l.selectedStyle = selectedStyle;
31952 l.unselectedStyle = unselectedStyle;
31953 l.hoverStyle = hoverStyle;
31954 this.naDiv.innerHTML = "Not available";
31955 l.div = this.naDiv;
31956
31957 if (map.options.labelGrid) {
31958 this.showPlacelabels();
31959 }
31960 };
31961
31962 this.showPlacelabels = function() {
31963 this.leftDiv = document.createElement("div");
31964 this.leftDiv.setAttribute('class', 'tagCloudDiv');
31965 this.leftDiv.style.textAlign = 'right';
31966 this.map.gui.mapWindow.appendChild(this.leftDiv);
31967 this.centerDiv = document.createElement("div");
31968 this.centerDiv.setAttribute('class', 'tagCloudDiv');
31969 this.centerDiv.style.opacity = 0.7;
31970 this.map.gui.mapWindow.appendChild(this.centerDiv);
31971 this.centerDivOl = document.createElement("div");
31972 this.centerDivOl.setAttribute('class', 'tagCloudDiv');
31973 this.centerDivOl.style.opacity = 0.7;
31974 this.map.gui.mapWindow.appendChild(this.centerDivOl);
31975 this.rightDiv = document.createElement("div");
31976 this.rightDiv.setAttribute('class', 'tagCloudDiv');
31977 this.rightDiv.style.textAlign = 'left';
31978 this.map.gui.mapWindow.appendChild(this.rightDiv);
31979 for (var i = 0; i < this.placeLabels.length; i++) {
31980 for (var j = 0; j < this.placeLabels[i].length; j++) {
31981 if (i == 0) {
31982 this.leftDiv.appendChild(this.placeLabels[i][j].div);
31983 } else {
31984 this.rightDiv.appendChild(this.placeLabels[i][j].div);
31985 }
31986 this.placeLabels[i][j].div.setAttribute('style', this.placeLabels[i][j].allStyle + "" + this.placeLabels[i][j].unselectedStyle);
31987 }
31988 }
31989 this.placeTagCloud();
31990 this.setCanvas();
31991 };
31992
31993 this.placeTagCloud = function() {
31994 var lonlat = new OpenLayers.LonLat(this.circle.feature.geometry.x, this.circle.feature.geometry.y);
31995 var pixel = map.openlayersMap.getPixelFromLonLat(lonlat);
31996 var radius = this.circle.feature.style.pointRadius;
31997 var lw = this.leftDiv.offsetWidth;
31998 var rw = this.rightDiv.offsetWidth;
31999 this.leftDiv.style.left = (pixel.x - radius - lw - 5) + "px";
32000 this.rightDiv.style.left = (pixel.x + radius + 5) + "px";
32001 var lh = this.leftDiv.offsetHeight;
32002 var rh = this.rightDiv.offsetHeight;
32003 var lt = pixel.y - lh / 2;
32004 var rt = pixel.y - rh / 2;
32005 this.leftDiv.style.top = lt + "px";
32006 this.rightDiv.style.top = rt + "px";
32007 };
32008
32009 this.setCanvas = function() {
32010 var height = Math.max(this.leftDiv.offsetHeight, this.rightDiv.offsetHeight);
32011 var top = Math.min(this.leftDiv.offsetTop, this.rightDiv.offsetTop);
32012 var left = this.leftDiv.offsetLeft + this.leftDiv.offsetWidth;
32013 this.width = this.rightDiv.offsetLeft - left;
32014 this.centerDiv.style.left = left + "px";
32015 this.centerDiv.style.top = top + "px";
32016 this.centerDiv.style.height = height + "px";
32017 this.centerDiv.style.width = this.width + "px";
32018
32019 this.centerDivOl.style.left = left + "px";
32020 this.centerDivOl.style.top = top + "px";
32021 this.centerDivOl.style.height = height + "px";
32022 this.centerDivOl.style.width = this.width + "px";
32023
32024 var cv = document.createElement("canvas");
32025 this.centerDiv.appendChild(cv);
32026 if (!cv.getContext && G_vmlCanvasManager) {
32027 cv = G_vmlCanvasManager.initElement(cv);
32028 }
32029 cv.width = this.width;
32030 cv.height = height;
32031 ctx = cv.getContext('2d');
32032
32033 this.cvOl = document.createElement("canvas");
32034 this.centerDivOl.appendChild(this.cvOl);
32035 if (!this.cvOl.getContext && G_vmlCanvasManager) {
32036 this.cvOl = G_vmlCanvasManager.initElement(this.cvOl);
32037 }
32038 this.cvOl.width = this.width;
32039 this.cvOl.height = height + 50;
32040 this.ctxOl = this.cvOl.getContext('2d');
32041
32042 for (var i = 0; i < this.placeLabels[0].length; i++) {
32043 this.placeLabels[0][i].opposite = false;
32044 }
32045 for (var i = 0; i < this.placeLabels[1].length; i++) {
32046 this.placeLabels[1][i].opposite = false;
32047 }
32048 for (var i = 0; i < this.placeLabels[0].length; i++) {
32049 for (var j = 0; j < this.placeLabels[1].length; j++) {
32050 if (this.placeLabels[0][i].place == this.placeLabels[1][j].place) {
32051 this.drawLine(ctx, this.placeLabels[0][i].div, this.placeLabels[1][j].div);
32052 this.placeLabels[0][i].opposite = true;
32053 this.placeLabels[1][j].opposite = true;
32054 }
32055 }
32056 }
32057 }
32058
32059 this.drawLine = function(ctx, label1, label2) {
32060 var x1 = 5;
32061 var x2 = this.width - 5;
32062 var y1 = label1.offsetTop + label1.offsetHeight / 2;
32063 var y2 = label2.offsetTop + label2.offsetHeight / 2;
32064 if (this.leftDiv.offsetTop > this.rightDiv.offsetTop) {
32065 y1 += this.leftDiv.offsetTop - this.rightDiv.offsetTop;
32066 } else {
32067 y2 += this.rightDiv.offsetTop - this.leftDiv.offsetTop;
32068 }
32069 ctx.lineCap = 'round';
32070 ctx.lineWidth = 5;
32071 ctx.beginPath();
32072 ctx.moveTo(x1, y1);
32073 ctx.lineTo(x2, y2);
32074 ctx.strokeStyle = '#555';
32075 ctx.stroke();
32076 }
32077
32078 this.remove = function() {
32079 $(this.leftDiv).remove();
32080 $(this.rightDiv).remove();
32081 $(this.centerDiv).remove();
32082 $(this.centerDivOl).remove();
32083 };
32084
32085 };
32086 /*
32087 * MapConfig.js
32088 *
32089 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
32090 *
32091 * This library is free software; you can redistribute it and/or
32092 * modify it under the terms of the GNU Lesser General Public
32093 * License as published by the Free Software Foundation; either
32094 * version 3 of the License, or (at your option) any later version.
32095 *
32096 * This library is distributed in the hope that it will be useful,
32097 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32098 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32099 * Lesser General Public License for more details.
32100 *
32101 * You should have received a copy of the GNU Lesser General Public
32102 * License along with this library; if not, write to the Free Software
32103 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
32104 * MA 02110-1301 USA
32105 */
32106
32107 /**
32108 * @class MapConfig
32109 * Map Configuration File
32110 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
32111 * @release 1.0
32112 * @release date: 2012-07-27
32113 * @version date: 2012-07-27
32114 */
32115 function MapConfig(options) {
32116
32117 this.options = {
32118 mapWidth : false, // false or desired width css definition for the map
32119 mapHeight : '580px', // false or desired height css definition for the map
32120 mapTitle : 'GeoTemCo Map View', // title will be shown in map header
32121 mapIndex : 0, // index = position in location array; for multiple locations the 2nd map refers to index 1
32122 alternativeMap : [
32123 {
32124 name: 'Barrington Roman Empire',
32125 url: 'http://pelagios.dme.ait.ac.at/tilesets/imperium/${z}/${x}/${y}.png',
32126 layer: 'namespace:layerName',
32127 type:'XYZ'
32128 },
32129 {
32130 name: 'Contemporary Map (1994)',
32131 url: 'http://dev2.dariah.eu/geoserver/wms',
32132 layer: 'historic:cntry1994'
32133 },
32134 {
32135 name: 'Historical Map of 1945',
32136 url: 'http://dev2.dariah.eu/geoserver/wms',
32137 layer: 'historic:cntry1945'
32138 },
32139 {
32140 name: 'Historical Map of 1938',
32141 url: 'http://dev2.dariah.eu/geoserver/wms',
32142 layer: 'historic:cntry1938'
32143 },
32144 {
32145 name: 'Historical Map of 1920',
32146 url: 'http://dev2.dariah.eu/geoserver/wms',
32147 layer: 'historic:cntry1920'
32148 },
32149 {
32150 name: 'Historical Map of 1914',
32151 url: 'http://dev2.dariah.eu/geoserver/wms',
32152 layer: 'historic:cntry1914'
32153 },
32154 {
32155 name: 'Historical Map of 1880',
32156 url: 'http://dev2.dariah.eu/geoserver/wms',
32157 layer: 'historic:cntry1880'
32158 },
32159 {
32160 name: 'Historical Map of 1815',
32161 url: 'http://dev2.dariah.eu/geoserver/wms',
32162 layer: 'historic:cntry1815'
32163 },
32164 {
32165 name: 'Historical Map of 1783',
32166 url: 'http://dev2.dariah.eu/geoserver/wms',
32167 layer: 'historic:cntry1783'
32168 },
32169 {
32170 name: 'Historical Map of 1715',
32171 url: 'http://dev2.dariah.eu/geoserver/wms',
32172 layer: 'historic:cntry1715'
32173 },
32174 {
32175 name: 'Historical Map of 1650',
32176 url: 'http://dev2.dariah.eu/geoserver/wms',
32177 layer: 'historic:cntry1650'
32178 },
32179 {
32180 name: 'Historical Map of 1530',
32181 url: 'http://dev2.dariah.eu/geoserver/wms',
32182 layer: 'historic:cntry1530'
32183 },
32184 {
32185 name: 'Historical Map of 1492',
32186 url: 'http://dev2.dariah.eu/geoserver/wms',
32187 layer: 'historic:cntry1492'
32188 },
32189 {
32190 name: 'Historical Map of 1279',
32191 url: 'http://dev2.dariah.eu/geoserver/wms',
32192 layer: 'historic:cntry1279'
32193 },
32194 {
32195 name: 'Historical Map of 1000',
32196 url: 'http://dev2.dariah.eu/geoserver/wms',
32197 layer: 'historic:cntry1000'
32198 },
32199 {
32200 name: 'Historical Map of 800',
32201 url: 'http://dev2.dariah.eu/geoserver/wms',
32202 layer: 'historic:cntry800'
32203 },
32204 {
32205 name: 'Historical Map of 600',
32206 url: 'http://dev2.dariah.eu/geoserver/wms',
32207 layer: 'historic:cntry600'
32208 },
32209 {
32210 name: 'Historical Map of 400',
32211 url: 'http://dev2.dariah.eu/geoserver/wms',
32212 layer: 'historic:cntry400'
32213 },
32214 {
32215 name: 'Historical Map of 1 BC',
32216 url: 'http://dev2.dariah.eu/geoserver/wms',
32217 layer: 'historic:cntry1bc'
32218 },
32219 {
32220 name: 'Historical Map of 200 BC',
32221 url: 'http://dev2.dariah.eu/geoserver/wms',
32222 layer: 'historic:cntry200bc'
32223 },
32224 {
32225 name: 'Historical Map of 323 BC',
32226 url: 'http://dev2.dariah.eu/geoserver/wms',
32227 layer: 'historic:cntry323bc'
32228 },
32229 {
32230 name: 'Historical Map of 500 BC',
32231 url: 'http://dev2.dariah.eu/geoserver/wms',
32232 layer: 'historic:cntry500bc'
32233 },
32234 {
32235 name: 'Historical Map of 1000 BC',
32236 url: 'http://dev2.dariah.eu/geoserver/wms',
32237 layer: 'historic:cntry1000bc'
32238 },
32239 {
32240 name: 'Historical Map of 2000 BC',
32241 url: 'http://dev2.dariah.eu/geoserver/wms',
32242 layer: 'historic:cntry2000bc'
32243 },
32244 ],
32245 legend : true, // if a legend at the bottom of the map should be shown or not
32246 mapMerge : false, // if the elements of distinct datasets should be merged into one set or not
32247 useGraphics : false, // if different graphics should represent different datasets or not
32248 graphics : [
32249 {
32250 shape: "circle",
32251 rotation: 0
32252 },
32253 {
32254 shape: "square",
32255 rotation: 0
32256 },
32257 {
32258 shape: "triangle",
32259 rotation: 0
32260 },
32261 {
32262 shape: "square",
32263 rotation: 45
32264 }
32265 ],
32266 googleMaps : false, // enable/disable Google maps (actually, no Google Maps API key is required)
32267 bingMaps : false, // enable/disable Bing maps (you need to set the Bing Maps API key below)
32268 bingApiKey : 'none', // bing maps api key, see informations at http://bingmapsportal.com/
32269 osmMaps : true, // enable/disable OSM maps
32270 osmMapsMapQuest : true, // enable/disable OSM maps with MapQuest tiles
32271 baseLayer : 'Open Street Map', // initial layer to show (e.g. 'Google Streets')
32272 resetMap : true, // show/hide map reset button
32273 countrySelect : true, // show/hide map country selection control button
32274 polygonSelect : true, // show/hide map polygon selection control button
32275 circleSelect : true, // show/hide map circle selection control button
32276 squareSelect : true, // show/hide map square selection control button
32277 multiSelection : true, // true, if multiple polygons or multiple circles should be selectable
32278 popups : true, // enabled popups will show popup windows for circles on the map
32279 olNavigation : false, // show/hide OpenLayers navigation panel
32280 olLayerSwitcher : false, // show/hide OpenLayers layer switcher
32281 olMapOverview : false, // show/hide OpenLayers map overview
32282 olKeyboardDefaults : true, // (de)activate Openlayers keyboard defaults
32283 olScaleLine : false, // (de)activate Openlayers keyboard defaults
32284 geoLocation : true, // show/hide GeoLocation feature
32285 boundaries : {
32286 minLon : -29,
32287 minLat : 35,
32288 maxLon : 44,
32289 maxLat : 67
32290 }, // initial map boundaries or 'false' for no boundaries
32291 mapBackground : '#bbd0ed',
32292 labelGrid : true, // show label grid on hover
32293 maxPlaceLabels : 6, // Integer value for fixed number of place labels: 0 --> unlimited, 1 --> 1 label (won't be shown in popup, 2 --> is not possible because of others & all labels --> 3 labels, [3,...,N] --> [3,...,N] place labels)
32294 selectDefault : true, // true, if strongest label should be selected as default
32295 maxLabelIncrease : 2, // maximum increase (in em) for the font size of a label
32296 labelHover : false, // true, to update on label hover
32297 ieHighlightLabel : "color: COLOR1; background-color: COLOR0; filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)';-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)';", // css code for a highlighted place label in IE
32298 highlightLabel : "color: COLOR0; text-shadow: 0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em COLOR0;", // css code for a highlighted place label
32299 ieSelectedLabel : "color: COLOR1; font-weight: bold;", // css code for a selected place label in IE
32300 selectedLabel : "color: COLOR1; font-weight: bold;", // css code for a selected place label
32301 ieUnselectedLabel : "color: COLOR1; font-weight: normal;", // css code for an unselected place label in IE
32302 unselectedLabel : "color: COLOR1; font-weight: normal;", // css code for an unselected place label
32303 ieHoveredLabel : "color: COLOR1; font-weight: bold;", // css code for a hovered place label in IE
32304 hoveredLabel : "color: COLOR1; font-weight: bold;", // css code for a hovered place label
32305 circleGap : 0, // gap between the circles on the map (>=0)
32306 circleOverlap : {
32307 type: 'area', // 'area' or 'diameter' is possible
32308 overlap: 0 // the percentage of allowed overlap (0<=overlap<=1)
32309 }, // maximum allowed overlap in percent (if circleGap = 0, circleOverlap will be used)
32310 minimumRadius : 4, // minimum radius of a circle with mimimal weight (>0)
32311 circleOutline : 2, // false for no outline or a pixel value v with 0 < v
32312 circleOpacity : 'balloon', // 'balloon' for dynamic opacity of the circles or a value t with 0 <= t <= 1
32313 minTransparency : 0.55, // maximum transparency of a circle
32314 maxTransparency : 0.8, // minimum transparency of a circle
32315 binning : 'generic', // binning algorithm for the map, possible values are: 'generic', 'square', 'hexagonal', 'triangular' or false for 'no binning'
32316 noBinningRadii : 'dynamic', // for 'no binning': 'static' for only minimum radii, 'dynamic' for increasing radii for increasing weights
32317 circlePackings : true, // if circles of multiple result sets should be displayed in circle packs, if a binning is performed
32318 binCount : 10, // number of bins for x and y dimension for lowest zoom level
32319 showDescriptions : true, // true to show descriptions of data items (must be provided by kml/json), false if not
32320 mapSelection : true, // show/hide select map dropdown
32321 binningSelection : false, // show/hide binning algorithms dropdown
32322 mapSelectionTools : true, // show/hide map selector tools
32323 dataInformation : true, // show/hide data information
32324 overlayVisibility : false, // initial visibility of additional overlays
32325 proxyHost : 'php/proxy.php?address=', //required for selectCountry feature, if the requested GeoServer and GeoTemCo are NOT on the same server
32326 placenameTagsStyle : 'value' // the style of the placenames "surrounding" a circle on hover. 'zoom' for tags based on zoom level (old behaviour), 'value' for new value-based
32327
32328 };
32329 if ( typeof options != 'undefined') {
32330 $.extend(this.options, options);
32331 }
32332
32333 };
32334
32335 MapConfig.prototype.getGraphic = function(id){
32336 var graphic = this.options.graphics[id % this.options.graphics.length];
32337 return {
32338 shape: graphic.shape,
32339 rotation: graphic.rotation,
32340 color: GeoTemConfig.getColor(Math.floor(id/this.options.graphics.length))
32341 };
32342 };
32343 /*
32344 * MapGui.js
32345 *
32346 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
32347 *
32348 * This library is free software; you can redistribute it and/or
32349 * modify it under the terms of the GNU Lesser General Public
32350 * License as published by the Free Software Foundation; either
32351 * version 3 of the License, or (at your option) any later version.
32352 *
32353 * This library is distributed in the hope that it will be useful,
32354 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32355 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32356 * Lesser General Public License for more details.
32357 *
32358 * You should have received a copy of the GNU Lesser General Public
32359 * License along with this library; if not, write to the Free Software
32360 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
32361 * MA 02110-1301 USA
32362 */
32363
32364 /**
32365 * @class MapGui
32366 * Map GUI Implementation
32367 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
32368 * @release 1.0
32369 * @release date: 2012-07-27
32370 * @version date: 2012-07-27
32371 *
32372 * @param {MapWidget} parent map widget object
32373 * @param {HTML object} div parent div to append the map gui
32374 * @param {JSON} options map configuration
32375 */
32376 function MapGui(map, div, options, iid) {
32377
32378 this.map = map;
32379
32380 this.container = div;
32381 if (options.mapWidth) {
32382 this.container.style.width = options.mapWidth;
32383 }
32384 if (options.mapHeight) {
32385 this.container.style.height = options.mapHeight;
32386 }
32387 this.container.style.position = 'relative';
32388
32389 this.mapWindow = document.createElement("div");
32390 this.mapWindow.setAttribute('class', 'mapWindow');
32391 this.mapWindow.id = "mapWindow"+iid;
32392 this.mapWindow.style.background = options.mapBackground;
32393 this.container.appendChild(this.mapWindow);
32394
32395 this.mapContainer = document.createElement("div");
32396 this.mapContainer.setAttribute('class', 'mapContainer');
32397 this.mapContainer.id = "mapContainer"+iid;
32398 this.mapContainer.style.position = "absolute";
32399 this.mapContainer.style.zIndex = 0;
32400 this.mapWindow.appendChild(this.mapContainer);
32401
32402 var toolbarTable = document.createElement("table");
32403 toolbarTable.setAttribute('class', 'absoluteToolbar ddbToolbar');
32404 this.container.appendChild(toolbarTable);
32405 this.mapToolbar = toolbarTable;
32406
32407 var titles = document.createElement("tr");
32408 toolbarTable.appendChild(titles);
32409 var tools = document.createElement("tr");
32410 toolbarTable.appendChild(tools);
32411
32412 if (options.mapSelection) {
32413 this.mapTypeTitle = document.createElement("td");
32414 titles.appendChild(this.mapTypeTitle);
32415 this.mapTypeTitle.innerHTML = GeoTemConfig.getString('mapType');
32416 this.mapTypeSelector = document.createElement("td");
32417 tools.appendChild(this.mapTypeSelector);
32418 }
32419
32420 if (options.mapSelectionTools) {
32421 this.mapSelectorTitle = document.createElement("td");
32422 titles.appendChild(this.mapSelectorTitle);
32423 this.mapSelectorTitle.innerHTML = GeoTemConfig.getString('mapSelectorTools');
32424 var mapSelectorTools = document.createElement("td");
32425 var selectorTools = this.map.initSelectorTools();
32426 for (var i in selectorTools ) {
32427 mapSelectorTools.appendChild(selectorTools[i].button);
32428 }
32429 tools.appendChild(mapSelectorTools);
32430 }
32431
32432 if (options.binningSelection) {
32433 this.binningTitle = document.createElement("td");
32434 titles.appendChild(this.binningTitle);
32435 this.binningTitle.innerHTML = GeoTemConfig.getString('binningType');
32436 this.binningSelector = document.createElement("td");
32437 tools.appendChild(this.binningSelector);
32438 }
32439
32440 if (GeoTemConfig.allowFilter) {
32441 this.filterTitle = document.createElement("td");
32442 titles.appendChild(this.filterTitle);
32443 this.filterTitle.innerHTML = GeoTemConfig.getString('filter');
32444 this.filterOptions = document.createElement("td");
32445 tools.appendChild(this.filterOptions);
32446 }
32447
32448 if (options.dataInformation) {
32449 this.infoTitle = document.createElement("td");
32450 this.infoTitle.innerHTML = options.mapTitle;
32451 titles.appendChild(this.infoTitle);
32452 var mapSum = document.createElement("td");
32453 this.mapElements = document.createElement("div");
32454 this.mapElements.setAttribute('class', 'ddbElementsCount');
32455 mapSum.appendChild(this.mapElements);
32456 tools.appendChild(mapSum);
32457 }
32458
32459 var gui = this;
32460 if (navigator.geolocation && options.geoLocation) {
32461 this.geoActive = false;
32462 this.geoLocation = document.createElement("div");
32463 this.geoLocation.setAttribute('class', 'geoLocationOff');
32464 this.geoLocation.title = GeoTemConfig.getString('activateGeoLocation');
32465 this.container.appendChild(this.geoLocation);
32466 this.geoLocation.style.left = "20px";
32467 this.geoLocation.onclick = function() {
32468 var changeStyle = function() {
32469 if (gui.geoActive) {
32470 gui.geoLocation.setAttribute('class', 'geoLocationOn');
32471 gui.geoLocation.title = GeoTemConfig.getString(GeoTemConfig.language, 'deactivateGeoLocation');
32472 } else {
32473 gui.geoLocation.setAttribute('class', 'geoLocationOff');
32474 gui.geoLocation.title = GeoTemConfig.getString(GeoTemConfig.language, 'activateGeoLocation');
32475 }
32476 }
32477 if (!gui.geoActive) {
32478 if ( typeof gui.longitude == 'undefined') {
32479 navigator.geolocation.getCurrentPosition(function(position) {
32480 gui.longitude = position.coords.longitude;
32481 gui.latitude = position.coords.latitude;
32482 gui.map.setMarker(gui.longitude, gui.latitude);
32483 gui.geoActive = true;
32484 changeStyle();
32485 }, function(msg) {
32486 console.log( typeof msg == 'string' ? msg : "error");
32487 });
32488 } else {
32489 gui.map.setMarker(gui.longitude, gui.latitude);
32490 gui.geoActive = true;
32491 changeStyle();
32492 }
32493 } else {
32494 gui.map.removeMarker();
32495 gui.geoActive = false;
32496 changeStyle();
32497 }
32498 }
32499 }
32500
32501 if (!options.olNavigation) {
32502 this.map.zoomSlider = new MapZoomSlider(this.map, "vertical");
32503 this.container.appendChild(this.map.zoomSlider.div);
32504 this.map.zoomSlider.div.style.left = "20px";
32505 }
32506
32507 if (options.resetMap) {
32508 this.homeButton = document.createElement("div");
32509 this.homeButton.setAttribute('class', 'mapHome');
32510 this.homeButton.title = GeoTemConfig.getString('home');
32511 this.container.appendChild(this.homeButton);
32512 this.homeButton.style.left = "20px";
32513 this.homeButton.onclick = function() {
32514 if (map.mds.getAllObjects() == null){
32515 map.openlayersMap.setCenter(new OpenLayers.LonLat(0, 0));
32516 map.openlayersMap.zoomTo(0);
32517 }
32518 gui.map.drawObjectLayer(true);
32519 }
32520 }
32521
32522 if (options.legend) {
32523 this.legendDiv = document.createElement("div");
32524 this.legendDiv.setAttribute('class', 'mapLegend');
32525 this.mapWindow.appendChild(this.legendDiv);
32526 }
32527
32528 var linkForOsm = 'http://www.openstreetmap.org/';
32529 var linkForLicense = 'http://creativecommons.org/licenses/by-sa/2.0/';
32530 this.osmLink = document.createElement("div");
32531 this.osmLink.setAttribute('class', 'osmLink');
32532 this.osmLink.innerHTML = '(c) <a href=' + linkForOsm + '>OpenStreetMap contributors</a>, <a href=' + linkForLicense + '>CC-BY-SA</a>';
32533 this.mapWindow.appendChild(this.osmLink);
32534 this.osmMapQuestLink = document.createElement("div");
32535 this.osmMapQuestLink.setAttribute('class', 'osmLink');
32536 this.osmMapQuestLink.innerHTML = '(c) Data, imagery and map information provided by MapQuest <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> <img src="http://developer.mapquest.com/content/osm/mq_logo.png"> <a href=' + linkForOsm + '>OpenStreetMap contributors</a>, <a href=' + linkForLicense + '>CC-BY-SA</a>';
32537 this.mapWindow.appendChild(this.osmMapQuestLink);
32538
32539 // var tooltip = document.createElement("div");
32540 // tooltip.setAttribute('class','ddbTooltip');
32541 // toolbarTable.appendChild(tooltip);
32542
32543 // var tooltip = document.createElement("div");
32544 // tooltip.setAttribute('class','ddbTooltip');
32545 // toolbarTable.appendChild(tooltip);
32546 //
32547 // tooltip.onmouseover = function(){
32548 // /*
32549 // Publisher.Publish('TooltipContent', {
32550 // content: GeoTemConfig.getString(GeoTemConfig.language,'timeHelp'),
32551 // target: $(tooltip)
32552 // });
32553 // */
32554 // }
32555 // tooltip.onmouseout = function(){
32556 // // Publisher.Publish('TooltipContent');
32557 // }
32558 // //vhz tooltip on click should open a help file if defined in GeoTemConfig
32559 // if(GeoTemConfig.helpURL) {
32560 // tooltip.onclick = function () {
32561 //
32562 // }
32563 // }
32564
32565 // }
32566 // tooltip.onmouseout = function(){
32567 // Publisher.Publish('TooltipContent');
32568 // }
32569
32570 this.resize = function() {
32571 var w = this.container.offsetWidth;
32572 var h = this.container.offsetHeight;
32573 // this.mapWindow.style.width = w + "px";
32574 this.mapWindow.style.height = h + "px";
32575 // this.mapContainer.style.width = w + "px";
32576 this.mapContainer.style.height = h + "px";
32577 var top = toolbarTable.offsetHeight + 20;
32578 if (options.olLayerSwitcher) {
32579 var switcherDiv = $('.olControlLayerSwitcher')[0];
32580 $(switcherDiv).css('top', top + "px");
32581 }
32582 if ( typeof this.geoLocation != "undefined") {
32583 this.geoLocation.style.top = top + "px";
32584 top += this.geoLocation.offsetHeight + 4;
32585 }
32586 if (options.olNavigation) {
32587 var panZoomBar = $('.olControlPanZoom')[0];
32588 $(panZoomBar).css('top', top + 'px');
32589 $(panZoomBar).css('left', '12px');
32590 var zoomOut = document.getElementById('OpenLayers.Control.PanZoom_23_zoomout');
32591 top += $(zoomOut).height() + $(zoomOut).position().top + 4;
32592 } else {
32593 this.map.zoomSlider.div.style.top = top + "px";
32594 top += this.map.zoomSlider.div.offsetHeight + 2;
32595 }
32596 if (options.resetMap) {
32597 this.homeButton.style.top = top + "px";
32598 }
32599 this.headerHeight = toolbarTable.offsetHeight;
32600 this.headerWidth = toolbarTable.offsetWidth;
32601 this.map.openlayersMap.updateSize();
32602 this.map.drawObjectLayer(true);
32603 };
32604
32605 this.updateLegend = function(datasets){
32606 $(this.legendDiv).empty();
32607 var table = $('<table style="margin:10px"/>').appendTo(this.legendDiv);
32608 for( var i=0; i<datasets.length; i++ ){
32609 var row = $('<tr/>').appendTo(table);
32610 if( options.useGraphics ){
32611 var graphic = map.config.getGraphic(i);
32612 var fill = 'rgb(' + graphic.color.r0 + ',' + graphic.color.g0 + ',' + graphic.color.b0 + ')';
32613 var stroke = 'rgb(' + graphic.color.r1 + ',' + graphic.color.g1 + ',' + graphic.color.b1 + ')';
32614 var rot = graphic.rotation;
32615 var svg;
32616 if( graphic.shape == 'circle' ){
32617 svg = '<svg style="width:20px;height:20px;"><circle cx="10" cy="10" r="7" stroke="'+stroke+'" stroke-width="2" fill="'+fill+'"/></svg>';
32618 }
32619 else if( graphic.shape == 'square' ){
32620 svg = '<svg style="width:20px;height:20px;"><polygon points="4,4 16,4 16,16 4,16" style="fill:'+fill+';stroke:'+stroke+';stroke-width:2" transform="rotate('+rot+' 10,10)"/></svg>';
32621 }
32622 else if( graphic.shape == 'triangle' ){
32623 svg = '<svg style="width:20px;height:20px;"><polygon points="3,17 17,17 10,5" style="fill:'+fill+';stroke:'+stroke+';stroke-width:2" transform="rotate('+rot+' 10,10)"/></svg>';
32624 }
32625 $('<td>'+svg+'</td>').appendTo(row);
32626 }
32627 else {
32628 var c = GeoTemConfig.getColor(i);
32629 var fill = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
32630 var stroke = 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')';
32631 var svg = '<svg style="width:20px;height:20px;"><circle cx="10" cy="10" r="7" stroke="'+stroke+'" stroke-width="2" fill="'+fill+'"/></svg>';
32632 $('<td>'+svg+'</td>').appendTo(row);
32633 }
32634 $('<td>'+datasets[i].label+'</td>').appendTo(row);
32635 }
32636 };
32637
32638 this.updateSpaceQuantity = function(count) {
32639 if (!options.dataInformation) {
32640 return;
32641 }
32642 this.mapCount = count;
32643 if (count != 1) {
32644 this.mapElements.innerHTML = this.beautifyCount(count) + " " + GeoTemConfig.getString('results');
32645 } else {
32646 this.mapElements.innerHTML = this.beautifyCount(count) + " " + GeoTemConfig.getString('result');
32647 }
32648 }
32649
32650 this.setMapsDropdown = function() {
32651 if (!options.mapSelection) {
32652 return;
32653 }
32654 $(this.mapTypeSelector).empty();
32655 var maps = [];
32656 var gui = this;
32657 var addMap = function(name, index) {
32658 var setMap = function() {
32659 gui.map.setMap(index);
32660 }
32661 maps.push({
32662 name : name,
32663 onclick : setMap
32664 });
32665 }
32666 for (var i = 0; i < this.map.baseLayers.length; i++) {
32667 addMap(this.map.baseLayers[i].name, i);
32668 }
32669 this.mapTypeDropdown = new Dropdown(this.mapTypeSelector, maps, GeoTemConfig.getString('selectMapType'));
32670 }
32671
32672 this.setMap = function() {
32673 if (options.mapSelection) {
32674 this.mapTypeDropdown.setEntry(this.map.baselayerIndex);
32675 }
32676 }
32677
32678 this.setBinningDropdown = function() {
32679 if (!options.binningSelection) {
32680 return;
32681 }
32682 $(this.binningSelector).empty();
32683 var binnings = [];
32684 var gui = this;
32685 var index = 0;
32686 var entry;
32687 var addBinning = function(name, id) {
32688 if (options.binning == id) {
32689 entry = index;
32690 } else {
32691 index++;
32692 }
32693 var setBinning = function() {
32694 options.binning = id;
32695 gui.map.initWidget(gui.map.datasets, false);
32696 gui.map.riseLayer();
32697 }
32698 binnings.push({
32699 name : name,
32700 onclick : setBinning
32701 });
32702 }
32703 addBinning(GeoTemConfig.getString('genericBinning'), 'generic');
32704 addBinning(GeoTemConfig.getString('squareBinning'), 'square');
32705 addBinning(GeoTemConfig.getString('hexagonalBinning'), 'hexagonal');
32706 addBinning(GeoTemConfig.getString('triangularBinning'), 'triangular');
32707 addBinning(GeoTemConfig.getString('noBinning'), false);
32708 var binningDropdown = new Dropdown(this.binningSelector, binnings, GeoTemConfig.getString('binningTooltip'));
32709 binningDropdown.setEntry(entry);
32710 }
32711 this.setBinningDropdown();
32712
32713 this.beautifyCount = function(count) {
32714 var c = count + '';
32715 var p = 0;
32716 var l = c.length;
32717 while (l - p > 3) {
32718 p += 3;
32719 c = c.substring(0, l - p) + "." + c.substring(l - p);
32720 p++;
32721 l++;
32722 }
32723 return c;
32724 }
32725
32726 };
32727 /*
32728 * MapWidget.js
32729 *
32730 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
32731 *
32732 * This library is free software; you can redistribute it and/or
32733 * modify it under the terms of the GNU Lesser General Public
32734 * License as published by the Free Software Foundation; either
32735 * version 3 of the License, or (at your option) any later version.
32736 *
32737 * This library is distributed in the hope that it will be useful,
32738 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32739 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32740 * Lesser General Public License for more details.
32741 *
32742 * You should have received a copy of the GNU Lesser General Public
32743 * License along with this library; if not, write to the Free Software
32744 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
32745 * MA 02110-1301 USA
32746 */
32747
32748 /**
32749 * @class MapWidget
32750 * MapWidget Implementation
32751 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
32752 * @release 1.0
32753 * @release date: 2012-07-27
32754 * @version date: 2012-07-27
32755 *
32756 * @param {MapWrapper} core wrapper for interaction to other widgets
32757 * @param {HTML object} div parent div to append the map widget div
32758 * @param {JSON} options user specified configuration that overwrites options in MapConfig.js
32759 */
32760 MapWidget = function(core, div, options) {
32761
32762 this.core = core;
32763 this.core.setWidget(this);
32764 this.openlayersMap
32765 this.baseLayers
32766 this.objectLayer
32767
32768 this.drawPolygon
32769 this.drawCircle
32770 this.selectCountry
32771 this.dragArea
32772 this.selectFeature
32773 this.navigation
32774
32775 this.div = div;
32776
32777 this.iid = GeoTemConfig.getIndependentId('map');
32778 this.config = new MapConfig(options);
32779 this.options = this.config.options;
32780 this.formerCP = this.options.circlePackings;
32781 this.gui = new MapGui(this, this.div, this.options, this.iid);
32782
32783 this.initialize();
32784
32785 }
32786
32787 MapWidget.prototype = {
32788
32789 /**
32790 * initializes the map for the Spatio Temporal Interface.
32791 * it includes setting up all layers of the map and defines all map specific interaction possibilities
32792 */
32793 initialize : function() {
32794
32795 var map = this;
32796
32797 //OpenLayers.ProxyHost = "/cgi-bin/proxy.cgi?url=";
32798 if (map.options.proxyHost) {
32799 OpenLayers.ProxyHost = map.options.proxyHost;
32800 }
32801
32802 this.polygons = [];
32803 this.connections = [];
32804 this.selection = new Selection();
32805 this.wmsOverlays = [];
32806
32807 this.layerZIndex = 1;
32808 this.zIndices = [];
32809
32810 var activateDrag = function() {
32811 map.dragArea.activate();
32812 }
32813 var deactivateDrag = function() {
32814 map.dragArea.deactivate();
32815 }
32816 this.dragControl = new MapControl(this, null, 'drag', activateDrag, deactivateDrag);
32817
32818 /*
32819 this.editPolygon = document.createElement("div");
32820 this.editPolygon.title = GeoTemConfig.getString('editPolygon');
32821 this.editPolygon.setAttribute('class','editMapPolygon');
32822 this.toolbar.appendChild(this.editPolygon);
32823 this.drag.onclick = function(evt){
32824 if( map.activeControl == "drag" ){
32825 map.deactivate("drag");
32826 if( GeoTemConfig.navigate ){
32827 map.activate("navigate");
32828 }
32829 }
32830 else {
32831 map.deactivate(map.activControl);
32832 map.activate("drag");
32833 }
32834 }
32835 map.addEditingMode(new OpenLayers.Control.EditingMode.PointArraySnapping());
32836 */
32837
32838 this.filterBar = new FilterBar(this, this.gui.filterOptions);
32839
32840 this.objectLayer = new OpenLayers.Layer.Vector("Data Objects", {
32841 projection : "EPSG:4326",
32842 'displayInLayerSwitcher' : false,
32843 rendererOptions : {
32844 zIndexing : true
32845 }
32846 });
32847
32848 this.markerLayer = new OpenLayers.Layer.Markers("Markers");
32849
32850 this.navigation = new OpenLayers.Control.Navigation({
32851 zoomWheelEnabled : GeoTemConfig.mouseWheelZoom
32852 });
32853 this.navigation.defaultDblClick = function(evt) {
32854 var newCenter = this.map.getLonLatFromViewPortPx(evt.xy);
32855 this.map.setCenter(newCenter, this.map.zoom + 1);
32856 map.drawObjectLayer(false);
32857 if (map.zoomSlider) {
32858 map.zoomSlider.setValue(map.openlayersMap.getZoom());
32859 }
32860 }
32861 this.navigation.wheelUp = function(evt) {
32862 this.wheelChange(evt, 1);
32863 map.drawObjectLayer(false);
32864 if (map.zoomSlider) {
32865 map.zoomSlider.setValue(map.openlayersMap.getZoom());
32866 }
32867 map.core.triggerHighlight([]);
32868 }
32869 this.navigation.wheelDown = function(evt) {
32870 this.wheelChange(evt, -1);
32871 map.drawObjectLayer(false);
32872 if (map.zoomSlider) {
32873 map.zoomSlider.setValue(map.openlayersMap.getZoom());
32874 }
32875 map.core.triggerHighlight([]);
32876 }
32877
32878 this.resolutions = [78271.516953125, 39135.7584765625, 19567.87923828125, 9783.939619140625, 4891.9698095703125, 2445.9849047851562, 1222.9924523925781, 611.4962261962891, 305.74811309814453, 152.87405654907226, 76.43702827453613, 38.218514137268066, 19.109257068634033, 9.554628534317017, 4.777314267158508, 2.388657133579254, 1.194328566789627, 0.5971642833948135, 0.29858214169740677];
32879
32880 var options = {
32881 controls : [this.navigation],
32882 projection : new OpenLayers.Projection("EPSG:900913"),
32883 displayProjection : new OpenLayers.Projection("EPSG:4326"),
32884 resolutions : this.resolutions,
32885 units : 'meters',
32886 maxExtent : new OpenLayers.Bounds(-20037508.34, -20037508.34, 20037508.34, 20037508.34)
32887 };
32888 this.openlayersMap = new OpenLayers.Map("mapContainer"+this.iid, options);
32889 if (map.options.navigate) {
32890 this.activeControl = "navigate";
32891 }
32892 this.mds = new MapDataSource(this.openlayersMap, this.options);
32893
32894 if (map.options.olNavigation) {
32895 var zoomPanel = new OpenLayers.Control.PanZoom();
32896 zoomPanel.onButtonClick = function(evt) {
32897 var btn = evt.buttonElement;
32898 switch (btn.action) {
32899 case "panup":
32900 this.map.pan(0, -this.getSlideFactor("h"));
32901 break;
32902 case "pandown":
32903 this.map.pan(0, this.getSlideFactor("h"));
32904 break;
32905 case "panleft":
32906 this.map.pan(-this.getSlideFactor("w"), 0);
32907 break;
32908 case "panright":
32909 this.map.pan(this.getSlideFactor("w"), 0);
32910 break;
32911 case "zoomin":
32912 map.zoom(1);
32913 break;
32914 case "zoomout":
32915 map.zoom(-1);
32916 break;
32917 case "zoomworld":
32918 if (this.map) {
32919 map.zoom(this.map.zoom * -1);
32920 }
32921 break;
32922 }
32923 };
32924 this.openlayersMap.addControl(zoomPanel);
32925 }
32926
32927 if (map.options.popups) {
32928 var panMap = function() {
32929 if (map.selectedGlyph) {
32930 var lonlat = new OpenLayers.LonLat(map.selectedGlyph.lon, map.selectedGlyph.lat);
32931 var pixel = map.openlayersMap.getPixelFromLonLat(lonlat);
32932 if (map.popup) {
32933 map.popup.shift(pixel.x, pixel.y);
32934 }
32935 }
32936 }
32937 this.openlayersMap.events.register("move", this.openlayersMap, panMap);
32938 }
32939
32940 if (map.options.olMapOverview) {
32941 this.openlayersMap.addControl(new OpenLayers.Control.OverviewMap());
32942 }
32943 if (map.options.olKeyboardDefaults) {
32944 var keyboardControl = new OpenLayers.Control.KeyboardDefaults();
32945 keyboardControl.defaultKeyPress = function(evt) {
32946 switch(evt.keyCode) {
32947 case OpenLayers.Event.KEY_LEFT:
32948 this.map.pan(-this.slideFactor, 0);
32949 break;
32950 case OpenLayers.Event.KEY_RIGHT:
32951 this.map.pan(this.slideFactor, 0);
32952 break;
32953 case OpenLayers.Event.KEY_UP:
32954 this.map.pan(0, -this.slideFactor);
32955 break;
32956 case OpenLayers.Event.KEY_DOWN:
32957 this.map.pan(0, this.slideFactor);
32958 break;
32959
32960 case 33:
32961 // Page Up. Same in all browsers.
32962 var size = this.map.getSize();
32963 this.map.pan(0, -0.75 * size.h);
32964 break;
32965 case 34:
32966 // Page Down. Same in all browsers.
32967 var size = this.map.getSize();
32968 this.map.pan(0, 0.75 * size.h);
32969 break;
32970 case 35:
32971 // End. Same in all browsers.
32972 var size = this.map.getSize();
32973 this.map.pan(0.75 * size.w, 0);
32974 break;
32975 case 36:
32976 // Home. Same in all browsers.
32977 var size = this.map.getSize();
32978 this.map.pan(-0.75 * size.w, 0);
32979 break;
32980
32981 case 43:
32982 // +/= (ASCII), keypad + (ASCII, Opera)
32983 case 61:
32984 // +/= (Mozilla, Opera, some ASCII)
32985 case 187:
32986 // +/= (IE)
32987 case 107:
32988 // keypad + (IE, Mozilla)
32989 map.zoom(1);
32990 break;
32991 case 45:
32992 // -/_ (ASCII, Opera), keypad - (ASCII, Opera)
32993 case 109:
32994 // -/_ (Mozilla), keypad - (Mozilla, IE)
32995 case 189:
32996 // -/_ (IE)
32997 case 95:
32998 // -/_ (some ASCII)
32999 map.zoom(-1);
33000 break;
33001 }
33002 };
33003 this.openlayersMap.addControl(keyboardControl);
33004 }
33005 if (map.options.olLayerSwitcher) {
33006 this.openlayersMap.addControl(new OpenLayers.Control.LayerSwitcher());
33007 }
33008 if (map.options.olScaleLine) {
33009 this.openlayersMap.addControl(new OpenLayers.Control.ScaleLine());
33010 }
33011 this.gui.resize();
33012 this.setBaseLayers();
33013 this.gui.setMapsDropdown();
33014 this.gui.setMap();
33015 this.openlayersMap.addLayers([this.objectLayer, this.markerLayer]);
33016
33017 if (map.options.boundaries) {
33018 var boundaries = map.options.boundaries;
33019 var bounds = new OpenLayers.Bounds(boundaries.minLon, boundaries.minLat, boundaries.maxLon, boundaries.maxLat);
33020 var projectionBounds = bounds.transform(this.openlayersMap.displayProjection, this.openlayersMap.projection);
33021 this.openlayersMap.zoomToExtent(projectionBounds);
33022 } else {
33023 this.openlayersMap.zoomToMaxExtent();
33024 }
33025
33026 // manages selection of elements if a polygon was drawn
33027 this.drawnPolygonHandler = function(polygon) {
33028 if (map.mds.getAllObjects() == null) {
33029 return;
33030 }
33031 var polygonFeature;
33032 if ( polygon instanceof OpenLayers.Geometry.Polygon) {
33033 polygonFeature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.MultiPolygon([polygon]));
33034 } else if ( polygon instanceof OpenLayers.Geometry.MultiPolygon) {
33035 polygonFeature = new OpenLayers.Feature.Vector(polygon);
33036 }
33037 map.polygons.push(polygonFeature);
33038 var style = $.extend(true, {}, OpenLayers.Feature.Vector.style['default']);
33039 style.graphicZIndex = 0;
33040 polygonFeature.style = style;
33041 map.objectLayer.addFeatures([polygonFeature]);
33042 try {
33043 map.activeControl.deactivate();
33044 } catch(e) {
33045 }
33046 var circles = map.mds.getObjectsByZoom();
33047 for (var i = 0; i < circles.length; i++) {
33048 for (var j = 0; j < circles[i].length; j++) {
33049 var c = circles[i][j];
33050 if (map.inPolygon(c)) {
33051 if ( typeof c.fatherBin != 'undefined') {
33052 for (var k = 0; k < c.fatherBin.circles.length; k++) {
33053 if (c.fatherBin.circles[k]) {
33054 c.fatherBin.circles[k].setSelection(true);
33055 }
33056 }
33057 } else {
33058 c.setSelection(true);
33059 }
33060 }
33061 }
33062 }
33063 map.mapSelection();
33064 }
33065
33066 this.polygonDeselection = function() {
33067 var circles = map.mds.getObjectsByZoom();
33068 for (var i = 0; i < circles.length; i++) {
33069 for (var j = 0; j < circles[i].length; j++) {
33070 var c = circles[i][j];
33071 if (map.inPolygon(c)) {
33072 c.setSelection(false);
33073 }
33074 }
33075 }
33076 }
33077 this.snapper = function() {
33078 if (map.polygons.length == 0 || !map.options.multiSelection) {
33079 map.deselection();
33080 }
33081 }
33082 if (map.options.polygonSelect) {
33083 this.drawPolygon = new OpenLayers.Control.DrawFeature(map.objectLayer, OpenLayers.Handler.Polygon, {
33084 displayClass : "olControlDrawFeaturePolygon",
33085 callbacks : {
33086 "done" : map.drawnPolygonHandler,
33087 "create" : map.snapper
33088 }
33089 });
33090 this.openlayersMap.addControl(this.drawPolygon);
33091 }
33092
33093 if (map.options.circleSelect) {
33094 this.drawCircle = new OpenLayers.Control.DrawFeature(map.objectLayer, OpenLayers.Handler.RegularPolygon, {
33095 displayClass : "olControlDrawFeaturePolygon",
33096 handlerOptions : {
33097 sides : 40
33098 },
33099 callbacks : {
33100 "done" : map.drawnPolygonHandler,
33101 "create" : map.snapper
33102 }
33103 });
33104 this.openlayersMap.addControl(this.drawCircle);
33105 }
33106
33107 if (map.options.squareSelect) {
33108 this.drawSquare = new OpenLayers.Control.DrawFeature(map.objectLayer, OpenLayers.Handler.RegularPolygon, {
33109 displayClass : "olControlDrawFeaturePolygon",
33110 handlerOptions : {
33111 sides : 4,
33112 irregular: true
33113 },
33114 callbacks : {
33115 "done" : map.drawnPolygonHandler,
33116 "create" : map.snapper
33117 }
33118 });
33119 this.openlayersMap.addControl(this.drawSquare);
33120 }
33121
33122 if (map.options.polygonSelect || map.options.circleSelect || map.options.squareSelect) {
33123 this.dragArea = new OpenLayers.Control.DragFeature(map.objectLayer, {
33124 onStart : function(feature) {
33125 feature.style.graphicZIndex = 10000;
33126 map.polygonDeselection();
33127 },
33128 onComplete : function(feature) {
33129 feature.style.graphicZIndex = 0;
33130 map.drawnPolygonHandler(feature.geometry);
33131 }
33132 });
33133 this.openlayersMap.addControl(this.dragArea);
33134
33135 this.modifyArea = new OpenLayers.Control.ModifyFeature(map.objectLayer, {
33136 onStart : function(feature) {
33137 feature.style.graphicZIndex = 10000;
33138 map.polygonDeselection();
33139 },
33140 onComplete : function(feature) {
33141 feature.style.graphicZIndex = 0;
33142 map.drawnPolygonHandler(feature.geometry);
33143 }
33144 });
33145 this.openlayersMap.addControl(this.modifyArea);
33146 this.modifyArea.mode = OpenLayers.Control.ModifyFeature.RESHAPE;
33147
33148 }
33149
33150 // calculates the tag cloud
33151 // manages hover selection of point objects
33152 var hoverSelect = function(event) {
33153 var object = event.feature;
33154 if (object.geometry instanceof OpenLayers.Geometry.Point) {
33155 if ( typeof map.placenameTags != 'undefined') {
33156 map.placenameTags.remove();
33157 }
33158 var circle = event.feature.parent;
33159 if ( circle instanceof CircleObject) {
33160 circle.placenameTags = new PlacenameTags(circle, map);
33161 map.placenameTags = circle.placenameTags;
33162 } else {
33163 return;
33164 /*
33165 event.feature.style.fillOpacity = 0.2;
33166 event.feature.style.strokeOpacity = 1;
33167 map.objectLayer.drawFeature(event.feature);
33168 circle.placenameTags = new PackPlacenameTags(circle,map);
33169 */
33170 }
33171 circle.placenameTags.calculate();
33172 map.mapCircleHighlight(object.parent, false);
33173 if ( typeof map.featureInfo != 'undefined') {
33174 map.featureInfo.deactivate();
33175 }
33176 } else {
33177 map.dragControl.checkStatus();
33178 }
33179 };
33180 var hoverUnselect = function(event) {
33181 var object = event.feature;
33182 if (object.geometry instanceof OpenLayers.Geometry.Point) {
33183 var circle = event.feature.parent;
33184 if (!( circle instanceof CircleObject )) {
33185 return;
33186 /*
33187 event.feature.style.fillOpacity = 0;
33188 event.feature.style.strokeOpacity = 0;
33189 map.objectLayer.drawFeature(event.feature);
33190 */
33191 }
33192 circle.placenameTags.remove();
33193 map.mapCircleHighlight(object.parent, true);
33194 if ( typeof map.featureInfo != 'undefined') {
33195 map.featureInfo.activate();
33196 }
33197 } else {
33198 map.dragControl.deactivate();
33199 }
33200 };
33201 var highlightCtrl = new OpenLayers.Control.SelectFeature(this.objectLayer, {
33202 hover : true,
33203 highlightOnly : true,
33204 renderIntent : "temporary",
33205 eventListeners : {
33206 featurehighlighted : hoverSelect,
33207 featureunhighlighted : hoverUnselect
33208 }
33209 });
33210 this.openlayersMap.addControl(highlightCtrl);
33211 highlightCtrl.activate();
33212
33213 this.selectFeature = new OpenLayers.Control.SelectFeature(this.objectLayer);
33214
33215 document.onkeydown = function(e) {
33216 if (e.ctrlKey) {
33217 map.ctrlKey = true;
33218 }
33219 }
33220 document.onkeyup = function(e) {
33221 map.ctrlKey = false;
33222 }
33223 // manages click selection of point objects
33224 var onFeatureSelect = function(event, evt) {
33225 if (!(event.feature.geometry instanceof OpenLayers.Geometry.Point)) {
33226 return;
33227 }
33228 var circle = event.feature.parent;
33229 if (map.options.multiSelection && map.ctrlKey) {
33230 if (map.popup) {
33231 map.popup.reset();
33232 map.selectedGlyph = false;
33233 }
33234 circle.toggleSelection();
33235 map.mapSelection();
33236 return;
33237 }
33238 map.reset();
33239 circle.setSelection(true);
33240 map.objectLayer.drawFeature(circle.feature);
33241 if (map.options.popups) {
33242 if (map.popup) {
33243 map.popup.reset();
33244 }
33245 var lonlat = event.feature.geometry.getBounds().getCenterLonLat();
33246 var pixel = map.openlayersMap.getPixelFromLonLat(lonlat);
33247 map.selectedGlyph = {
33248 lon : lonlat.lon,
33249 lat : lonlat.lat
33250 };
33251 map.popup = new PlacenamePopup(map);
33252 map.popup.createPopup(pixel.x, pixel.y, circle.placenameTags.placeLabels);
33253 if (map.options.selectDefault) {
33254 circle.placenameTags.selectLabel();
33255 }
33256 }
33257 }
33258 this.objectLayer.events.on({
33259 "featureselected" : onFeatureSelect
33260 });
33261
33262 this.openlayersMap.addControl(this.selectFeature);
33263 this.selectFeature.activate();
33264
33265 if (this.zoomSlider) {
33266 this.zoomSlider.setMaxAndLevels(1000, this.openlayersMap.getNumZoomLevels());
33267 this.zoomSlider.setValue(this.openlayersMap.getZoom());
33268 }
33269
33270 Publisher.Subscribe('mapChanged', this, function(mapName) {
33271 this.client.setBaseLayerByName(mapName);
33272 this.client.gui.setMap();
33273 });
33274
33275 },
33276
33277 shift : function(shiftX, shiftY) {
33278 this.openlayersMap.pan(shiftX, shiftY);
33279 },
33280
33281 addBaseLayers : function(layers) {
33282 if ( layers instanceof Array) {
33283 for (var i in layers ) {
33284 var layer;
33285 if (layers[i].type === "XYZ"){
33286 layer = new OpenLayers.Layer.XYZ(
33287 layers[i].name,
33288 [
33289 layers[i].url
33290 ],
33291 {
33292 sphericalMercator: true,
33293 transitionEffect: "resize",
33294 buffer: 1,
33295 numZoomLevels: 12,
33296 transparent : true
33297 },
33298 {
33299 isBaseLayer : true
33300 }
33301 );
33302 } else {
33303 layer = new OpenLayers.Layer.WMS(
33304 layers[i].name, layers[i].url,
33305 {
33306 projection : "EPSG:4326",
33307 layers : layers[i].layer,
33308 transparent : "true",
33309 format : "image/png"
33310 },
33311 {
33312 isBaseLayer : true
33313 }
33314 );
33315 }
33316 this.baseLayers.push(layer);
33317 this.openlayersMap.addLayers([layer]);
33318 }
33319 }
33320 this.gui.setMapsDropdown();
33321 },
33322
33323 /**
33324 * set online available maps for Google, Bing and OSM
33325 */
33326 setBaseLayers : function() {
33327 this.baseLayers = [];
33328 if (this.options.googleMaps) {
33329 // see http://openlayers.org/blog/2010/07/10/google-maps-v3-for-openlayers/ for information
33330 var gphy = new OpenLayers.Layer.Google("Google Physical", {
33331 type : google.maps.MapTypeId.TERRAIN,
33332 minZoomLevel : 1,
33333 maxZoomLevel : 19
33334 });
33335 var gmap = new OpenLayers.Layer.Google("Google Streets", {
33336 minZoomLevel : 1,
33337 maxZoomLevel : 19
33338 });
33339 var ghyb = new OpenLayers.Layer.Google("Google Hybrid", {
33340 type : google.maps.MapTypeId.HYBRID,
33341 minZoomLevel : 1,
33342 maxZoomLevel : 19
33343 });
33344 var gsat = new OpenLayers.Layer.Google("Google Satellite", {
33345 type : google.maps.MapTypeId.SATELLITE,
33346 minZoomLevel : 1,
33347 maxZoomLevel : 19
33348 });
33349 this.baseLayers.push(gphy);
33350 this.baseLayers.push(gmap);
33351 this.baseLayers.push(ghyb);
33352 this.baseLayers.push(gsat);
33353 }
33354 if (this.options.bingMaps) {
33355 // see http://openlayers.org/blog/2010/12/18/bing-tiles-for-openlayers/ for information
33356 var apiKey = this.options.bingApiKey;
33357 var road = new OpenLayers.Layer.Bing({
33358 name : "Road",
33359 key : apiKey,
33360 type : "Road"
33361 });
33362 var hybrid = new OpenLayers.Layer.Bing({
33363 name : "Hybrid",
33364 key : apiKey,
33365 type : "AerialWithLabels"
33366 });
33367 var aerial = new OpenLayers.Layer.Bing({
33368 name : "Aerial",
33369 key : apiKey,
33370 type : "Aerial"
33371 });
33372 this.baseLayers.push(road);
33373 this.baseLayers.push(hybrid);
33374 this.baseLayers.push(aerial);
33375 }
33376 if (this.options.osmMaps) {
33377 this.baseLayers.push(new OpenLayers.Layer.OSM('Open Street Map', '', {
33378 sphericalMercator : true,
33379 zoomOffset : 1,
33380 resolutions : this.resolutions
33381 }));
33382 }
33383 if (this.options.osmMapsMapQuest) {
33384 this.baseLayers.push(new OpenLayers.Layer.OSM('Open Street Map (MapQuest)',
33385 ["http://otile1.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png",
33386 "http://otile2.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png",
33387 "http://otile3.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png",
33388 "http://otile4.mqcdn.com/tiles/1.0.0/map/${z}/${x}/${y}.png"],
33389 {
33390 sphericalMercator : true,
33391 zoomOffset : 1,
33392 resolutions : this.resolutions
33393 }
33394 ));
33395 }
33396 for (var i = 0; i < this.baseLayers.length; i++) {
33397 this.openlayersMap.addLayers([this.baseLayers[i]]);
33398 }
33399 if (this.options.alternativeMap) {
33400 if (!(this.options.alternativeMap instanceof Array))
33401 this.options.alternativeMap = [this.options.alternativeMap];
33402 this.addBaseLayers(this.options.alternativeMap);
33403 }
33404 this.setBaseLayerByName(this.options.baseLayer);
33405 },
33406
33407 setBaseLayerByName : function(name){
33408 for (var i = 0; i < this.baseLayers.length; i++) {
33409 if (this.baseLayers[i].name == name) {
33410 this.setMap(i);
33411 }
33412 }
33413 },
33414
33415 getBaseLayerName : function() {
33416 return this.openlayersMap.baseLayer.name;
33417 },
33418
33419 setOverlays : function(layers) {
33420 var map = this;
33421 for (var i in this.wmsOverlays ) {
33422 this.openlayersMap.removeLayer(this.wmsOverlays[i]);
33423 }
33424 this.wmsOverlays = [];
33425 var featureInfoLayers = [];
33426 if ( layers instanceof Array) {
33427 for (var i in layers ) {
33428 var layer = new OpenLayers.Layer.WMS(layers[i].name, layers[i].url, {
33429 projection : "EPSG:4326",
33430 layers : layers[i].layer,
33431 transparent : "true",
33432 format : "image/png"
33433 }, {
33434 isBaseLayer : false,
33435 visibility : map.options.overlayVisibility
33436 });
33437 this.wmsOverlays.push(layer);
33438 if (layers[i].featureInfo) {
33439 featureInfoLayers.push(layer);
33440 }
33441 }
33442 this.openlayersMap.addLayers(this.wmsOverlays);
33443 }
33444 if (this.wmsOverlays.length > 0 && map.options.overlayVisibility) {
33445 var map = this;
33446 if ( typeof this.featureInfo != 'undefined') {
33447 this.featureInfo.deactivate();
33448 this.openlayersMap.removeControl(this.featureInfo);
33449 }
33450 this.featureInfo = new OpenLayers.Control.WMSGetFeatureInfo({
33451 url : '/geoserver/wms',
33452 layers : featureInfoLayers,
33453 eventListeners : {
33454 getfeatureinfo : function(event) {
33455 if (event.text == '') {
33456 return;
33457 }
33458 var lonlat = map.openlayersMap.getLonLatFromPixel(new OpenLayers.Pixel(event.xy.x, event.xy.y));
33459 map.selectedGlyph = {
33460 lon : lonlat.lon,
33461 lat : lonlat.lat
33462 };
33463 if ( typeof map.popup != 'undefined') {
33464 map.popup.reset();
33465 }
33466 map.popup = new MapPopup(map);
33467 map.popup.initialize(event.xy.x, event.xy.y);
33468 map.popup.setContent(event.text);
33469 }
33470 }
33471 });
33472 this.openlayersMap.addControl(this.featureInfo);
33473 this.featureInfo.activate();
33474 this.activateCountrySelector(this.wmsOverlays[this.wmsOverlays.length - 1]);
33475 } else {
33476 this.deactivateCountrySelector();
33477 if (this.openlayersMap.baseLayer instanceof OpenLayers.Layer.WMS) {
33478 this.activateCountrySelector(this.openlayersMap.baseLayer);
33479 }
33480 }
33481 },
33482
33483 addBaseLayer : function(layer) {
33484 this.baseLayers.push(layer);
33485 this.openlayersMap.addLayers([layer]);
33486 for (var i in this.baseLayers ) {
33487 if (this.baseLayers[i].name == this.options.baseLayer) {
33488 this.setMap(i);
33489 }
33490 }
33491 },
33492
33493 /**
33494 * draws the object layer.
33495 * @param {boolean} zoom if there was a zoom; if not, the new boundary of the map is calculated
33496 */
33497 drawObjectLayer : function(zoom) {
33498 if ( typeof this.placenameTags != 'undefined') {
33499 this.placenameTags.remove();
33500 }
33501 var points = this.mds.getAllObjects();
33502 if (points == null) {
33503 return;
33504 }
33505 this.objectLayer.removeAllFeatures();
33506
33507 if (zoom) {
33508 var minLat, maxLat, minLon, maxLon;
33509 var pointsHighestZoom = points[points.length - 1];
33510 for (var i = 0; i < pointsHighestZoom.length; i++) {
33511 for (var j = 0; j < pointsHighestZoom[i].length; j++) {
33512 var point = pointsHighestZoom[i][j];
33513 if (minLon == null || point.originX < minLon) {
33514 minLon = point.originX;
33515 }
33516 if (maxLon == null || point.originX > maxLon) {
33517 maxLon = point.originX;
33518 }
33519 if (minLat == null || point.originY < minLat) {
33520 minLat = point.originY;
33521 }
33522 if (maxLat == null || point.originY > maxLat) {
33523 maxLat = point.originY;
33524 }
33525 }
33526 }
33527 if (minLon == maxLon && minLat == maxLat) {
33528 this.openlayersMap.setCenter(new OpenLayers.LonLat(minLon, minLat));
33529 } else {
33530 var gapX = 0.1 * (maxLon - minLon );
33531 var gapY1 = 0.1 * (maxLat - minLat );
33532 var gapY2 = (this.gui.headerHeight / this.gui.mapWindow.offsetHeight + 0.1 ) * (maxLat - minLat );
33533 this.openlayersMap.zoomToExtent(new OpenLayers.Bounds(minLon - gapX, minLat - gapY1, maxLon + gapX, maxLat + gapY2));
33534 this.openlayersMap.zoomTo(Math.floor(this.openlayersMap.getZoom()));
33535 }
33536 if (this.zoomSlider) {
33537 this.zoomSlider.setValue(this.openlayersMap.getZoom());
33538 }
33539 }
33540 var displayPoints = this.mds.getObjectsByZoom();
33541 var resolution = this.openlayersMap.getResolution();
33542 for (var i = 0; i < displayPoints.length; i++) {
33543 for (var j = 0; j < displayPoints[i].length; j++) {
33544 var p = displayPoints[i][j];
33545 var x = p.originX + resolution * p.shiftX;
33546 var y = p.originY + resolution * p.shiftY;
33547 p.feature.geometry.x = x;
33548 p.feature.geometry.y = y;
33549 p.olFeature.geometry.x = x;
33550 p.olFeature.geometry.y = y;
33551 p.feature.style.graphicZIndex = this.zIndices[i];
33552 p.olFeature.style.graphicZIndex = this.zIndices[i] + 1;
33553 this.objectLayer.addFeatures([p.feature]);
33554 this.objectLayer.addFeatures([p.olFeature]);
33555 }
33556 }
33557 var zoomLevel = this.openlayersMap.getZoom();
33558 /*
33559 for (var i = 0; i < this.bins[zoomLevel].length; i++) {
33560 var p = this.bins[zoomLevel][i];
33561 p.feature.style.graphicZIndex = 0;
33562 this.objectLayer.addFeatures([p.feature]);
33563 }
33564 */
33565
33566 var dist = function(p1, p2) {
33567 return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
33568 }
33569
33570 this.highlightChanged(this.selection.getObjects(this.core));
33571
33572 },
33573
33574 riseLayer : function(id) {
33575 this.lastId = id;
33576 if ( typeof id == 'undefined') {
33577 id = this.lastId || 0;
33578 }
33579 this.zIndices[id] = this.layerZIndex;
33580 this.layerZIndex += 2;
33581 this.drawObjectLayer(false);
33582 for( var i=0; i<this.polygons.length; i++ ){
33583 this.objectLayer.addFeatures([this.polygons[i]]);
33584 }
33585 },
33586
33587 /**
33588 * initializes the object layer.
33589 * all point representations for all zoom levels are calculated and initialized
33590 * @param {MapObject[][]} mapObjects an array of map objects from different (1-4) sets
33591 */
33592 initWidget : function(datasets, zoom) {
33593
33594 this.clearMap();
33595
33596 this.datasets = datasets;
33597 var mapObjects = [];
33598 for (var i = 0; i < datasets.length; i++) {
33599 mapObjects.push(datasets[i].objects);
33600 }
33601 if (mapObjects.length > 4) {
33602 this.options.circlePackings = false;
33603 } else {
33604 this.options.circlePackings = this.formerCP;
33605 }
33606
33607 if ( typeof mapObjects == 'undefined') {
33608 return;
33609 }
33610
33611 this.count = 0;
33612 this.objectCount = 0;
33613 for (var i = 0; i < mapObjects.length; i++) {
33614 var c = 0;
33615 for (var j = 0; j < mapObjects[i].length; j++) {
33616 if (mapObjects[i][j].isGeospatial) {
33617 c += mapObjects[i][j].weight;
33618 this.objectCount++;
33619 }
33620 }
33621 this.count += c;
33622 this.zIndices.push(this.layerZIndex);
33623 this.layerZIndex += 2;
33624 }
33625
33626 this.mds.initialize(mapObjects);
33627 var points = this.mds.getAllObjects();
33628 if (points == null) {
33629 return;
33630 }
33631
33632 var getArea = function(radius) {
33633 return Math.PI * radius * radius;
33634 }
33635 for (var i = 0; i < points.length; i++) {
33636 var area = 0;
33637 var maxRadius = 0;
33638 for (var j = 0; j < points[i].length; j++) {
33639 for (var k = 0; k < points[i][j].length; k++) {
33640 if (points[i][j][k].radius > maxRadius) {
33641 maxRadius = points[i][j][k].radius;
33642 area = getArea(maxRadius);
33643 }
33644 }
33645 }
33646 var minArea = getArea(this.options.minimumRadius);
33647 var areaDiff = area - minArea;
33648 for (var j = 0; j < points[i].length; j++) {
33649 for (var k = 0; k < points[i][j].length; k++) {
33650 var point = points[i][j][k];
33651 var c, shape, rotation, multiplier = 1;
33652 if( this.options.useGraphics ){
33653 var graphic = this.config.getGraphic(point.search);
33654 c = graphic.color;
33655 shape = graphic.shape;
33656 rotation = graphic.rotation;
33657 if( shape == 'square' ){
33658 multiplier = 0.75;
33659 }
33660 }
33661 else {
33662 c = GeoTemConfig.getAverageDatasetColor(point.search,point.elements);
33663 shape = 'circle';
33664 rotation = 0;
33665 }
33666 var opacity;
33667 if (this.options.circleOpacity == 'balloon') {
33668 var min = this.options.minTransparency;
33669 var max = this.options.maxTransparency;
33670 opacity = min + Math.abs(min - max) * (1 - (getArea(point.radius) - minArea) / areaDiff);
33671 }
33672 else {
33673 opacity = this.options.circleOpacity;
33674 }
33675 var col = false, ols = 0;
33676 if( this.options.circleOutline ){
33677 col = true;
33678 ols = this.options.circleOutline;
33679 }
33680 var style = {
33681 graphicName: shape,
33682 rotation: rotation,
33683 fillColor : 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')',
33684 fillOpacity : opacity,
33685 strokeWidth : ols,
33686 strokeColor : 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')',
33687 stroke : col,
33688 pointRadius : point.radius * multiplier,
33689 cursor : "pointer"
33690 };
33691 var pointGeometry = new OpenLayers.Geometry.Point(point.originX, point.originY, null);
33692 var feature = new OpenLayers.Feature.Vector(pointGeometry);
33693 feature.style = style;
33694 feature.parent = point;
33695 point.setFeature(feature);
33696 var olStyle = {
33697 graphicName: shape,
33698 rotation: rotation,
33699 fillColor : 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')',
33700 fillOpacity : opacity,
33701 stroke : false,
33702 pointRadius : 0,
33703 cursor : "pointer"
33704 };
33705 var olPointGeometry = new OpenLayers.Geometry.Point(point.originX, point.originY, null);
33706 var olFeature = new OpenLayers.Feature.Vector(olPointGeometry);
33707 olFeature.style = olStyle;
33708 olFeature.parent = point;
33709 point.setOlFeature(olFeature);
33710 }
33711 }
33712 }
33713
33714 /*
33715 this.bins = this.mds.getAllBins();
33716 for (var i = 0; i < this.bins.length; i++) {
33717 for (var j = 0; j < this.bins[i].length; j++) {
33718 var bin = this.bins[i][j];
33719 var style = {
33720 fillColor : 'rgb(140,140,140)',
33721 fillOpacity : 0,
33722 strokeWidth : 2,
33723 strokeOpacity : 0,
33724 strokeColor : 'rgb(140,140,140)',
33725 // stroke: false,
33726 pointRadius : bin.radius,
33727 cursor : "pointer"
33728 };
33729 var pointGeometry = new OpenLayers.Geometry.Point(bin.x, bin.y, null);
33730 var feature = new OpenLayers.Feature.Vector(pointGeometry);
33731 feature.style = style;
33732 feature.parent = bin;
33733 bin.feature = feature;
33734 }
33735 }
33736 */
33737
33738 this.gui.updateLegend(datasets);
33739
33740 if ( typeof zoom == "undefined") {
33741 this.drawObjectLayer(true);
33742 } else {
33743 this.drawObjectLayer(zoom);
33744 }
33745 this.gui.updateSpaceQuantity(this.count);
33746
33747 },
33748
33749 /**
33750 * resets the map by destroying all additional elements except the point objects, which are replaced
33751 */
33752 reset : function() {
33753 if ( typeof this.placenameTags != 'undefined') {
33754 this.placenameTags.remove();
33755 }
33756 this.objectLayer.removeFeatures(this.polygons);
33757 this.polygons = [];
33758 this.objectLayer.removeFeatures(this.connections);
33759 this.connections = [];
33760 this.selectFeature.unselectAll();
33761 this.selectedGlyph = false;
33762 if (this.dragControl.activated) {
33763 this.dragControl.deactivate();
33764 }
33765 if (this.popup) {
33766 this.popup.reset();
33767 }
33768 this.filterBar.reset(false);
33769 var points = this.mds.getObjectsByZoom();
33770 if (points == null) {
33771 return;
33772 }
33773 for (var i = 0; i < points.length; i++) {
33774 for (var j = 0; j < points[i].length; j++) {
33775 points[i][j].setSelection(false);
33776 }
33777 }
33778 },
33779
33780 /**
33781 * resets the map by destroying all elements
33782 */
33783 clearMap : function() {
33784 this.reset();
33785 this.selection = new Selection();
33786 this.zIndices = [];
33787 this.layerZIndex = 1;
33788 this.objectLayer.destroyFeatures();
33789 },
33790
33791 /**
33792 * updates the proportional selection status of a point object
33793 * @param {PointObject} point the point to update
33794 * @param {OpenLayers.Geometry.Polygon} polygon the actual displayed map polygon
33795 */
33796 updatePoint : function(point, polygon) {
33797 var olRadius = this.mds.binning.getRadius(point.overlay);
33798 if( this.options.useGraphics ){
33799 var graphic = this.config.getGraphic(point.search);
33800 if( graphic.shape == 'square' ){
33801 olRadius *= 0.75;
33802 }
33803 }
33804 point.olFeature.style.pointRadius = olRadius;
33805 var c = GeoTemConfig.getAverageDatasetColor(point.search, point.overlayElements);
33806 point.olFeature.style.fillColor = 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')';
33807 if (polygon.containsPoint(point.feature.geometry)) {
33808 this.objectLayer.drawFeature(point.olFeature);
33809 }
33810 },
33811
33812 /**
33813 * updates the the object layer of the map after selections had been executed in timeplot or table or zoom level has changed
33814 */
33815 highlightChanged : function(mapObjects) {
33816 if( !GeoTemConfig.highlightEvents ){
33817 return;
33818 }
33819 this.mds.clearOverlay();
33820 if (this.selection.valid()) {
33821 this.mds.setOverlay(GeoTemConfig.mergeObjects(mapObjects, this.selection.getObjects()));
33822 } else {
33823 this.mds.setOverlay(mapObjects);
33824 }
33825 var points = this.mds.getObjectsByZoom();
33826 var polygon = this.openlayersMap.getExtent().toGeometry();
33827 for (var i in points ) {
33828 for (var j in points[i] ) {
33829 this.updatePoint(points[i][j], polygon);
33830 }
33831 }
33832 this.displayConnections();
33833 },
33834
33835 selectionChanged : function(selection) {
33836 if( !GeoTemConfig.selectionEvents ){
33837 return;
33838 }
33839 this.reset();
33840 this.selection = selection;
33841 this.highlightChanged(selection.objects);
33842 },
33843
33844 inPolygon : function(point) {
33845 for (var i = 0; i < this.polygons.length; i++) {
33846 var polygon = this.polygons[i].geometry;
33847 for (var j = 0; j < polygon.components.length; j++) {
33848 if (polygon.components[j].containsPoint(point.feature.geometry)) {
33849 return true;
33850 }
33851 }
33852 }
33853 return false;
33854 },
33855
33856 mapSelection : function() {
33857 var selectedObjects = [];
33858 for (var i = 0; i < this.mds.size(); i++) {
33859 selectedObjects.push([]);
33860 }
33861 var circles = this.mds.getObjectsByZoom();
33862 for (var i = 0; i < circles.length; i++) {
33863
33864 for (var j = 0; j < circles[i].length; j++) {
33865 var c = circles[i][j];
33866 if (c.selected) {
33867 selectedObjects[i] = selectedObjects[i].concat(c.elements);
33868 }
33869 }
33870 }
33871 this.selection = new Selection(selectedObjects, this);
33872 this.highlightChanged(selectedObjects);
33873 this.core.triggerSelection(this.selection);
33874 this.filterBar.reset(true);
33875 },
33876
33877 deselection : function() {
33878 this.reset();
33879 this.selection = new Selection();
33880 this.highlightChanged([]);
33881 this.core.triggerSelection(this.selection);
33882 },
33883
33884 filtering : function() {
33885 for (var i = 0; i < this.datasets.length; i++) {
33886 this.datasets[i].objects = this.selection.objects[i];
33887 }
33888 this.core.triggerRefining(this.datasets);
33889 },
33890
33891 inverseFiltering : function() {
33892 var selectedObjects = [];
33893 for (var i = 0; i < this.mds.size(); i++) {
33894 selectedObjects.push([]);
33895 }
33896 var circles = this.mds.getObjectsByZoom();
33897 for (var i = 0; i < circles.length; i++) {
33898 for (var j = 0; j < circles[i].length; j++) {
33899 var c = circles[i][j];
33900 if (!c.selected) {
33901 selectedObjects[i] = selectedObjects[i].concat(c.elements);
33902 }
33903 }
33904 }
33905 this.selection = new Selection(selectedObjects, this);
33906 this.filtering();
33907 },
33908
33909 mapCircleHighlight : function(circle, undo) {
33910 if (this.polygons.length > 0 && this.inPolygon(circle)) {
33911 return;
33912 }
33913 var mapObjects = [];
33914 for (var i = 0; i < this.mds.size(); i++) {
33915 mapObjects.push([]);
33916 }
33917 if (!undo && !circle.selected) {
33918 mapObjects[circle.search] = circle.elements;
33919 }
33920 this.objectLayer.drawFeature(circle.feature);
33921 this.core.triggerHighlight(mapObjects);
33922 },
33923
33924 mapLabelSelection : function(label) {
33925 var selectedObjects = [];
33926 for (var i = 0; i < this.mds.size(); i++) {
33927 selectedObjects.push([]);
33928 }
33929 selectedObjects[label.index] = label.elements;
33930 this.selection = new Selection(selectedObjects, this);
33931 this.highlightChanged(selectedObjects);
33932 this.core.triggerSelection(this.selection);
33933 this.filterBar.reset(true);
33934 },
33935
33936 triggerMapChanged : function(mapName) {
33937 Publisher.Publish('mapChanged', mapName, this);
33938 },
33939
33940 /**
33941 * displays connections between data objects
33942 */
33943 displayConnections : function() {
33944 return;
33945 if ( typeof this.connection != 'undefined') {
33946 this.objectLayer.removeFeatures(this.connections);
33947 this.connections = [];
33948 }
33949 if (this.options.connections) {
33950 var points = this.mds.getObjectsByZoom();
33951 for (var i in points ) {
33952 for (var j in points[i] ) {
33953
33954 }
33955 }
33956
33957 var slices = this.core.timeplot.getSlices();
33958 for (var i = 0; i < slices.length; i++) {
33959 for (var j = 0; j < slices[i].stacks.length; j++) {
33960 var e = slices[i].stacks[j].elements;
33961 if (e.length == 0) {
33962 continue;
33963 }
33964 var points = [];
33965 for (var k = 0; k < e.length; k++) {
33966 var point = this.mds.getCircle(j, e[k].index).feature.geometry;
33967 if (arrayIndex(points, point) == -1) {
33968 points.push(point);
33969 }
33970 }
33971 var matrix = new AdjMatrix(points.length);
33972 for (var k = 0; k < points.length - 1; k++) {
33973 for (var l = k + 1; l < points.length; l++) {
33974 matrix.setEdge(k, l, dist(points[k], points[l]));
33975 }
33976 }
33977 var tree = Prim(matrix);
33978 var lines = [];
33979 for (var z = 0; z < tree.length; z++) {
33980 lines.push(new OpenLayers.Geometry.LineString(new Array(points[tree[z].v1], points[tree[z].v2])));
33981 }
33982 this.connections[j].push({
33983 first : this.mds.getCircle(j, e[0].index).feature.geometry,
33984 last : this.mds.getCircle(j, e[e.length - 1].index).feature.geometry,
33985 lines : lines,
33986 time : slices[i].date
33987 });
33988 }
33989 }
33990 var ltm = this.core.timeplot.leftFlagTime;
33991 var rtm = this.core.timeplot.rightFlagTime;
33992 if (ltm == undefined || ltm == null) {
33993 return;
33994 } else {
33995 ltm = ltm.getTime();
33996 rtm = rtm.getTime();
33997 }
33998 // this.connectionLayer.destroyFeatures();
33999 if (thisConnections) {
34000 for (var i = 0; i < this.connections.length; i++) {
34001 var c = GeoTemConfig.colors[i];
34002 var style = {
34003 strokeColor : 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')',
34004 strokeOpacity : 0.5,
34005 strokeWidth : 3
34006 };
34007 var pointsToConnect = [];
34008 var last = undefined;
34009 for (var j = 0; j < this.connections[i].length; j++) {
34010 var c = this.connections[i][j];
34011 var ct = c.time.getTime();
34012 if (ct >= ltm && ct <= rtm) {
34013 if (last != undefined) {
34014 var line = new OpenLayers.Geometry.LineString(new Array(last, c.first));
34015 this.connectionLayer.addFeatures([new OpenLayers.Feature.Vector(line, null, style)]);
34016 }
34017 for (var k = 0; k < c.lines.length; k++) {
34018 this.connectionLayer.addFeatures([new OpenLayers.Feature.Vector(c.lines[k], null, style)]);
34019 }
34020 last = c.last;
34021 }
34022 }
34023 }
34024 // this.connectionLayer.redraw();
34025 }
34026 }
34027 },
34028
34029 /**
34030 * performs a zoom on the map
34031 * @param {int} delta the change of zoom levels
34032 */
34033 zoom : function(delta) {
34034 var zoom = this.openlayersMap.getZoom() + delta;
34035 if (this.openlayersMap.baseLayer instanceof OpenLayers.Layer.WMS) {
34036 this.openlayersMap.zoomTo(zoom);
34037 } else {
34038 this.openlayersMap.zoomTo(Math.round(zoom));
34039 if (this.zoomSlider) {
34040 this.zoomSlider.setValue(this.openlayersMap.getZoom());
34041 }
34042 }
34043 this.drawObjectLayer(false);
34044 return true;
34045 },
34046
34047 deactivateCountrySelector : function() {
34048 this.openlayersMap.removeControl(this.selectCountry);
34049 this.selectCountry = undefined;
34050 },
34051
34052 activateCountrySelector : function(layer) {
34053 var map = this;
34054 if (this.options.countrySelect && this.options.mapSelectionTools) {
34055 this.selectCountry = new OpenLayers.Control.GetFeature({
34056 protocol : OpenLayers.Protocol.WFS.fromWMSLayer(layer),
34057 click : true
34058 });
34059 this.selectCountry.events.register("featureselected", this, function(e) {
34060 map.snapper();
34061 map.drawnPolygonHandler(e.feature.geometry);
34062 });
34063 this.openlayersMap.addControl(this.selectCountry);
34064 this.countrySelectionControl.enable();
34065 }
34066 },
34067
34068 setMap : function(index) {
34069 this.baselayerIndex = index;
34070 if (this.selectCountry) {
34071 // if( this.wmsOverlays.length == 0 ){
34072 this.deactivateCountrySelector();
34073 // }
34074 }
34075 if (this.baseLayers[index] instanceof OpenLayers.Layer.WMS) {
34076 // if( this.wmsOverlays.length == 0 ){
34077 this.activateCountrySelector(this.baseLayers[index]);
34078 // }
34079 } else {
34080 if (this.countrySelectionControl) {
34081 this.countrySelectionControl.disable();
34082 }
34083 }
34084 this.openlayersMap.zoomTo(Math.floor(this.openlayersMap.getZoom()));
34085 this.openlayersMap.setBaseLayer(this.baseLayers[index]);
34086 if (this.baseLayers[index].name == 'Open Street Map') {
34087 this.gui.osmLink.style.visibility = 'visible';
34088 } else {
34089 this.gui.osmLink.style.visibility = 'hidden';
34090 }
34091 if (this.baseLayers[index].name == 'Open Street Map (MapQuest)') {
34092 this.gui.osmMapQuestLink.style.visibility = 'visible';
34093 } else {
34094 this.gui.osmMapQuestLink.style.visibility = 'hidden';
34095 }
34096 this.triggerMapChanged(this.baseLayers[index].name);
34097 },
34098
34099 //vhz added title to buttons
34100 initSelectorTools : function() {
34101 var map = this;
34102 this.mapControls = [];
34103
34104 if (this.options.squareSelect) {
34105 var button = document.createElement("div");
34106 $(button).addClass('mapControl');
34107 var activate = function() {
34108 map.drawSquare.activate();
34109 }
34110 var deactivate = function() {
34111 map.drawSquare.deactivate();
34112 }
34113 this.mapControls.push(new MapControl(this, button, 'square', activate, deactivate));
34114 }
34115 if (this.options.circleSelect) {
34116 var button = document.createElement("div");
34117 $(button).addClass('mapControl');
34118 var activate = function() {
34119 map.drawCircle.activate();
34120 }
34121 var deactivate = function() {
34122 map.drawCircle.deactivate();
34123 }
34124 this.mapControls.push(new MapControl(this, button, 'circle', activate, deactivate));
34125 }
34126 if (this.options.polygonSelect) {
34127 var button = document.createElement("div");
34128 $(button).addClass('mapControl');
34129 var activate = function() {
34130 map.drawPolygon.activate();
34131 }
34132 var deactivate = function() {
34133 map.drawPolygon.deactivate();
34134 }
34135 this.mapControls.push(new MapControl(this, button, 'polygon', activate, deactivate));
34136 }
34137 if (this.options.countrySelect) {
34138 var button = document.createElement("div");
34139 $(button).addClass('mapControl');
34140 var activate = function() {
34141 map.selectCountry.activate();
34142 map.dragControl.disable();
34143 }
34144 var deactivate = function() {
34145 map.selectCountry.deactivate();
34146 map.dragControl.enable();
34147 }
34148 this.countrySelectionControl = new MapControl(this, button, 'country', activate, deactivate);
34149 this.mapControls.push(this.countrySelectionControl);
34150 /*
34151 if( !(this.openlayersMap.baseLayer instanceof OpenLayers.Layer.WMS) ){
34152 this.countrySelectionControl.disable();
34153 }
34154 */
34155 }
34156 return this.mapControls;
34157 },
34158
34159 getZoom : function() {
34160 return this.openlayersMap.getZoom();
34161 },
34162
34163 setMarker : function(lon, lat) {
34164 var p = new OpenLayers.Geometry.Point(lon, lat, null);
34165 p.transform(this.openlayersMap.displayProjection, this.openlayersMap.projection);
34166 this.openlayersMap.setCenter(new OpenLayers.LonLat(p.x, p.y));
34167 var size = new OpenLayers.Size(22, 33);
34168 var offset = new OpenLayers.Pixel(-(size.w / 2), -size.h);
34169 var icon = new OpenLayers.Icon(GeoTemConfig.path + 'marker.png', size, offset);
34170 var marker = new OpenLayers.Marker(new OpenLayers.LonLat(p.x, p.y), icon);
34171 marker.setOpacity(0.9);
34172 this.markerLayer.setZIndex(parseInt(this.objectLayer.getZIndex()) + 1);
34173 this.markerLayer.addMarker(marker);
34174 // find nearest neighbor
34175 var nearestNeighbor;
34176 var points = this.mds.getAllObjects();
34177 if (points == null) {
34178 return;
34179 }
34180 var dist = function(p1, p2) {
34181 return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
34182 }
34183 var zoomLevels = this.openlayersMap.getNumZoomLevels();
34184 var pointSet = points[zoomLevels - 1];
34185 var closestDistance = undefined;
34186 var closestPoint;
34187 for (var i = 0; i < pointSet.length; i++) {
34188 for (var j = 0; j < pointSet[i].length; j++) {
34189 var point = pointSet[i][j].feature.geometry;
34190 var d = dist(point, p);
34191 if (!closestDistance || d < closestDistance) {
34192 closestDistance = d;
34193 closestPoint = point;
34194 }
34195 }
34196 }
34197 // find minimal zoom level
34198 var gap = 0;
34199 var x_s = this.gui.mapWindow.offsetWidth / 2 - gap;
34200 var y_s = this.gui.mapWindow.offsetHeight / 2 - gap;
34201 if (typeof closestPoint !== "undefined"){
34202 var xDist = Math.abs(p.x - closestPoint.x);
34203 var yDist = Math.abs(p.y - closestPoint.y);
34204 for (var i = 0; i < zoomLevels; i++) {
34205 var resolution = this.openlayersMap.getResolutionForZoom(zoomLevels - i - 1);
34206 if (xDist / resolution < x_s && yDist / resolution < y_s) {
34207 this.openlayersMap.zoomTo(zoomLevels - i - 1);
34208 if (this.zoomSlider) {
34209 this.zoomSlider.setValue(this.openlayersMap.getZoom());
34210 }
34211 this.drawObjectLayer(false);
34212 break;
34213 }
34214 }
34215 } else {
34216 //if there are no points on the map, zoom to max
34217 this.openlayersMap.zoomTo(0);
34218 if (this.zoomSlider) {
34219 this.zoomSlider.setValue(this.openlayersMap.getZoom());
34220 }
34221 this.drawObjectLayer(false);
34222 }
34223 },
34224
34225 removeMarker : function() {
34226 this.markerLayer.removeMarker(this.markerLayer.markers[0]);
34227 },
34228
34229 getLevelOfDetail : function() {
34230 var zoom = Math.floor(this.openlayersMap.getZoom());
34231 if (zoom <= 1) {
34232 return 0;
34233 } else if (zoom <= 3) {
34234 return 1;
34235 } else if (zoom <= 8) {
34236 return 2;
34237 } else {
34238 return 3;
34239 }
34240 }
34241 }
34242 /*
34243 * TimeConfig.js
34244 *
34245 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
34246 *
34247 * This library is free software; you can redistribute it and/or
34248 * modify it under the terms of the GNU Lesser General Public
34249 * License as published by the Free Software Foundation; either
34250 * version 3 of the License, or (at your option) any later version.
34251 *
34252 * This library is distributed in the hope that it will be useful,
34253 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34254 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34255 * Lesser General Public License for more details.
34256 *
34257 * You should have received a copy of the GNU Lesser General Public
34258 * License along with this library; if not, write to the Free Software
34259 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
34260 * MA 02110-1301 USA
34261 */
34262
34263 /**
34264 * @class TimeConfig
34265 * Time Configuration File
34266 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
34267 * @release 1.0
34268 * @release date: 2012-07-27
34269 * @version date: 2012-07-27
34270 */
34271 function TimeConfig(options) {
34272
34273 this.options = {
34274 timeTitle : 'GeoTemCo Time View', // title will be shown in timeplot header
34275 timeIndex : 0, // index = position in date array; for multiple dates the 2nd timeplot refers to index 1
34276 timeWidth : false, // false or desired width css definition for the timeplot
34277 timeHeight : '100px', // false or desired height css definition for the timeplot
34278 defaultMinDate : new Date(2012, 0, 1), // required, when empty timelines are possible
34279 defaultMaxDate : new Date(), // required, when empty timelines are possible
34280 timeCanvasFrom : '#EEE', // time widget background gradient color top
34281 timeCanvasTo : '#EEE', // time widget background gradient color bottom
34282 rangeBoxColor : "white", // fill color for time range box
34283 rangeBorder : "1px solid #de7708", // border of frames
34284 dataInformation : true, // show/hide data information
34285 rangeAnimation : true, // show/hide animation buttons
34286 scaleSelection : true, // show/hide scale selection buttons
34287 linearScale : true, // true for linear value scaling, false for logarithmic
34288 unitSelection : true, // show/hide time unit selection dropdown
34289 timeUnit : -1, // minimum temporal unit (SimileAjax.DateTime or -1 if none) of the data
34290 timeMerge : false // if the elements of distinct datasets should be merged into one set or not
34291 };
34292 if ( typeof options != 'undefined') {
34293 $.extend(this.options, options);
34294 }
34295
34296 };
34297 /*
34298 * TimeGui.js
34299 *
34300 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
34301 *
34302 * This library is free software; you can redistribute it and/or
34303 * modify it under the terms of the GNU Lesser General Public
34304 * License as published by the Free Software Foundation; either
34305 * version 3 of the License, or (at your option) any later version.
34306 *
34307 * This library is distributed in the hope that it will be useful,
34308 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34309 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34310 * Lesser General Public License for more details.
34311 *
34312 * You should have received a copy of the GNU Lesser General Public
34313 * License along with this library; if not, write to the Free Software
34314 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
34315 * MA 02110-1301 USA
34316 */
34317
34318 /**
34319 * @class TimeGui
34320 * Time GUI Implementation
34321 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
34322 * @release 1.0
34323 * @release date: 2012-07-27
34324 * @version date: 2012-07-27
34325 *
34326 * @param {TimeWidget} parent time widget object
34327 * @param {HTML object} div parent div to append the time gui
34328 * @param {JSON} options time configuration
34329 */
34330 function TimeGui(plot, div, options, iid) {
34331
34332 var gui = this;
34333
34334 this.plot = plot;
34335
34336 this.container = div;
34337 if (options.timeWidth) {
34338 this.container.style.width = options.timeWidth;
34339 }
34340 if (options.timeHeight) {
34341 this.container.style.height = options.timeHeight;
34342 }
34343 this.container.style.position = 'relative';
34344
34345 var w = this.container.offsetWidth;
34346 var h = this.container.offsetHeight;
34347
34348 var toolbarTable = document.createElement("table");
34349 toolbarTable.setAttribute('class', 'ddbToolbar');
34350 this.container.appendChild(toolbarTable);
34351
34352 this.plotWindow = document.createElement("div");
34353 this.plotWindow.id = "plotWindow"+iid;
34354 this.plotWindow.setAttribute('class', 'plotWindow');
34355 // this.plotWindow.style.width = w + "px";
34356
34357 this.plotWindow.style.height = (h + 12) + "px";
34358 this.container.style.height = (h + 12) + "px";
34359
34360 this.plotWindow.onmousedown = function() {
34361 return false;
34362 }
34363
34364 this.plotContainer = document.createElement("div");
34365 this.plotContainer.id = "plotContainer"+iid;
34366 this.plotContainer.setAttribute('class', 'plotContainer');
34367 // this.plotContainer.style.width = w + "px";
34368 this.plotContainer.style.height = h + "px";
34369 this.plotContainer.style.position = "absolute";
34370 this.plotContainer.style.zIndex = 0;
34371 this.plotContainer.style.top = "12px";
34372 this.plotWindow.appendChild(this.plotContainer);
34373 this.container.appendChild(this.plotWindow);
34374
34375 this.timeplotDiv = document.createElement("div");
34376 this.timeplotDiv.style.left = "16px";
34377 this.timeplotDiv.style.width = (w - 32) + "px";
34378 this.timeplotDiv.style.height = h + "px";
34379 this.plotContainer.appendChild(this.timeplotDiv);
34380
34381 var cv = document.createElement("canvas");
34382 cv.setAttribute('class', 'plotCanvas');
34383 this.plotWindow.appendChild(cv);
34384 if (!cv.getContext && G_vmlCanvasManager)
34385 cv = G_vmlCanvasManager.initElement(cv);
34386 var ctx = cv.getContext('2d');
34387
34388 var setCanvas = function(){
34389 cv.width = gui.plotWindow.clientWidth;
34390 cv.height = gui.plotWindow.clientHeight;
34391 var gradient = ctx.createLinearGradient(0, 0, 0, gui.plotWindow.clientHeight);
34392 gradient.addColorStop(0, options.timeCanvasFrom);
34393 gradient.addColorStop(1, options.timeCanvasTo);
34394 ctx.fillStyle = gradient;
34395 ctx.fillRect(0, 0, gui.plotWindow.clientWidth, gui.plotWindow.clientHeight);
34396 }
34397 setCanvas();
34398
34399 this.resize = function(){
34400 gui.timeplotDiv.style.width = (gui.container.offsetWidth - 32) + "px";
34401 ctx.clearRect(0,0,gui.plotWindow.clientWidth, gui.plotWindow.clientHeight);
34402 if( typeof plot.datasets != "undefined" ){
34403 plot.redrawPlot();
34404 plot.resetOpacityPlots();
34405 }
34406 setCanvas();
34407 };
34408
34409 var titles = document.createElement("tr");
34410 toolbarTable.appendChild(titles);
34411 var tools = document.createElement("tr");
34412 toolbarTable.appendChild(tools);
34413
34414 this.timeUnitTitle = document.createElement("td");
34415 this.timeUnitTitle.innerHTML = GeoTemConfig.getString('timeUnit');
34416 this.timeUnitSelector = document.createElement("td");
34417 if (options.unitSelection) {
34418 tools.appendChild(this.timeUnitSelector);
34419 titles.appendChild(this.timeUnitTitle);
34420 }
34421
34422 this.timeAnimation = document.createElement("td");
34423 this.timeAnimation.innerHTML = GeoTemConfig.getString('timeAnimation');
34424 var timeAnimationTools = document.createElement("td");
34425
34426 var status;
34427 this.updateAnimationButtons = function(s) {
34428 status = s;
34429 if (status == 0) {
34430 gui.playButton.setAttribute('class', 'smallButton playDisabled');
34431 gui.pauseButton.setAttribute('class', 'smallButton pauseDisabled');
34432 } else if (status == 1) {
34433 gui.playButton.setAttribute('class', 'smallButton playEnabled');
34434 gui.pauseButton.setAttribute('class', 'smallButton pauseDisabled');
34435 } else {
34436 gui.playButton.setAttribute('class', 'smallButton playDisabled');
34437 gui.pauseButton.setAttribute('class', 'smallButton pauseEnabled');
34438 }
34439 };
34440 this.playButton = document.createElement("div");
34441 this.playButton.title = GeoTemConfig.getString('playButton');
34442 timeAnimationTools.appendChild(this.playButton);
34443 this.playButton.onclick = function() {
34444 if (status == 1) {
34445 plot.play();
34446 }
34447 }
34448
34449 this.pauseButton = document.createElement("div");
34450 this.pauseButton.title = GeoTemConfig.getString('pauseButton');
34451 timeAnimationTools.appendChild(this.pauseButton);
34452 this.pauseButton.onclick = function() {
34453 if (status == 2) {
34454 plot.stop();
34455 }
34456 }
34457
34458 this.valueScale = document.createElement("td");
34459 this.valueScale.innerHTML = GeoTemConfig.getString('valueScale');
34460 var valueScaleTools = document.createElement("td");
34461
34462 var linearPlot;
34463 var setValueScale = function(linScale) {
34464 if (linearPlot != linScale) {
34465 linearPlot = linScale;
34466 if (linearPlot) {
34467 gui.linButton.setAttribute('class', 'smallButton linearPlotActivated');
34468 gui.logButton.setAttribute('class', 'smallButton logarithmicPlotDeactivated');
34469 plot.drawLinearPlot();
34470 } else {
34471 gui.linButton.setAttribute('class', 'smallButton linearPlotDeactivated');
34472 gui.logButton.setAttribute('class', 'smallButton logarithmicPlotActivated');
34473 plot.drawLogarithmicPlot();
34474 }
34475 }
34476 };
34477 this.linButton = document.createElement("div");
34478 this.linButton.title = GeoTemConfig.getString('linearPlot');
34479 valueScaleTools.appendChild(this.linButton);
34480 this.linButton.onclick = function() {
34481 setValueScale(true);
34482 }
34483
34484 this.logButton = document.createElement("div");
34485 this.logButton.title = GeoTemConfig.getString('logarithmicPlot');
34486 valueScaleTools.appendChild(this.logButton);
34487 this.logButton.onclick = function() {
34488 setValueScale(false);
34489 }
34490 if (options.rangeAnimation) {
34491 titles.appendChild(this.timeAnimation);
34492 tools.appendChild(timeAnimationTools);
34493 this.updateAnimationButtons(0);
34494 }
34495
34496 if (options.scaleSelection) {
34497 titles.appendChild(this.valueScale);
34498 tools.appendChild(valueScaleTools);
34499 setValueScale(options.linearScale);
34500 }
34501
34502 if (GeoTemConfig.allowFilter) {
34503 this.filterTitle = document.createElement("td");
34504 titles.appendChild(this.filterTitle);
34505 this.filterTitle.innerHTML = GeoTemConfig.getString('filter');
34506 this.filterOptions = document.createElement("td");
34507 tools.appendChild(this.filterOptions);
34508 }
34509
34510 if (options.dataInformation) {
34511 this.infoTitle = document.createElement("td");
34512 this.infoTitle.innerHTML = options.timeTitle;
34513 titles.appendChild(this.infoTitle);
34514 var timeSum = document.createElement("td");
34515 this.timeElements = document.createElement("div");
34516 this.timeElements.setAttribute('class', 'ddbElementsCount');
34517 timeSum.appendChild(this.timeElements);
34518 tools.appendChild(timeSum);
34519 }
34520
34521 /*
34522 var tooltip = document.createElement("div");
34523 tooltip.setAttribute('class','ddbTooltip');
34524 toolbarTable.appendChild(tooltip);
34525
34526 tooltip.onmouseover = function(){
34527 /*
34528 getPublisher().Publish('TooltipContent', {
34529 content: GeoTemConfig.getString(GeoTemConfig.language,'timeHelp'),
34530 target: $(tooltip)
34531 });
34532
34533 }
34534 tooltip.onmouseout = function(){
34535 //getPublisher().Publish('TooltipContent');
34536 }
34537 */
34538
34539 this.setHeight = function() {
34540 this.container.style.height = (this.plotWindow.offsetHeight + toolbarTable.offsetHeight) + "px";
34541 };
34542
34543 this.updateTimeQuantity = function(count) {
34544 if (options.dataInformation) {
34545 this.plotCount = count;
34546 if (count != 1) {
34547 this.timeElements.innerHTML = this.beautifyCount(count) + " " + GeoTemConfig.getString('results');
34548 } else {
34549 this.timeElements.innerHTML = this.beautifyCount(count) + " " + GeoTemConfig.getString('result');
34550 }
34551 }
34552 }
34553
34554 this.setTimeUnitDropdown = function(units) {
34555 $(this.timeUnitSelector).empty();
34556 var gui = this;
34557 var timeUnits = [];
34558 var addUnit = function(unit, index) {
34559 var setUnit = function() {
34560 gui.plot.setTimeUnit(unit.unit);
34561 }
34562 timeUnits.push({
34563 name : unit.label,
34564 onclick : setUnit
34565 });
34566 }
34567 for (var i = 0; i < units.length; i++) {
34568 addUnit(units[i], i);
34569 }
34570 this.timeUnitDropdown = new Dropdown(this.timeUnitSelector, timeUnits, GeoTemConfig.getString('selectTimeUnit'), '100px');
34571 this.timeUnitDropdown.setEntry(0);
34572 }
34573 this.setTimeUnitDropdown([{
34574 name : 'none',
34575 id : -1
34576 }]);
34577
34578 this.beautifyCount = function(count) {
34579 var c = count + '';
34580 var p = 0;
34581 var l = c.length;
34582 while (l - p > 3) {
34583 p += 3;
34584 c = c.substring(0, l - p) + "." + c.substring(l - p);
34585 p++;
34586 l++;
34587 }
34588 return c;
34589 }
34590
34591 this.hideTimeUnitSelection = function() {
34592 this.timeUnitTitle.style.display = 'none';
34593 this.timeUnitSelector.style.display = 'none';
34594 }
34595 };
34596 /*
34597 * TimeWidget.js
34598 *
34599 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
34600 *
34601 * This library is free software; you can redistribute it and/or
34602 * modify it under the terms of the GNU Lesser General Public
34603 * License as published by the Free Software Foundation; either
34604 * version 3 of the License, or (at your option) any later version.
34605 *
34606 * This library is distributed in the hope that it will be useful,
34607 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34608 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34609 * Lesser General Public License for more details.
34610 *
34611 * You should have received a copy of the GNU Lesser General Public
34612 * License along with this library; if not, write to the Free Software
34613 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
34614 * MA 02110-1301 USA
34615 */
34616
34617 /**
34618 * @class TimeWidget
34619 * TableWidget Implementation
34620 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
34621 * @release 1.0
34622 * @release date: 2012-07-27
34623 * @version date: 2012-07-27
34624 *
34625 * @param {TimeWrapper} core wrapper for interaction to other widgets
34626 * @param {HTML object} div parent div to append the time widget div
34627 * @param {JSON} options user specified configuration that overwrites options in TimeConfig.js
34628 */
34629 TimeWidget = function(core, div, options) {
34630
34631 this.core = core;
34632 this.core.setWidget(this);
34633 this.timeplot
34634 this.dataSources
34635 this.eventSources
34636 this.tds
34637 this.timeGeometry
34638 this.valueGeometry
34639 this.canvas
34640
34641 this.leftFlagPole
34642 this.rightFlagPole
34643 this.rangeBox
34644 this.leftHandle
34645 this.rightHandle
34646
34647 this.leftFlagPos = null;
34648 this.leftFlagTime = null;
34649 this.rightFlagPos = null;
34650 this.rightFlagTime = null;
34651
34652 this.mouseDownTime
34653 this.mouseUpTime
34654 this.mouseTempTime
34655 this.mouseDownPos
34656 this.mouseUpPos
34657 this.mouseTempPos
34658
34659 this.status
34660 this.slider
34661
34662 this.iid = GeoTemConfig.getIndependentId('time');
34663 this.options = (new TimeConfig(options)).options;
34664 this.gui = new TimeGui(this, div, this.options, this.iid);
34665 this.initialize();
34666
34667 }
34668
34669 TimeWidget.prototype = {
34670
34671 /**
34672 * clears the timeplot canvas and the timeGeometry properties
34673 */
34674 clearTimeplot : function() {
34675 this.timeplot._clearCanvas();
34676 this.timeGeometry._earliestDate = null;
34677 this.timeGeometry._latestDate = null;
34678 this.valueGeometry._minValue = 0;
34679 this.valueGeometry._maxValue = 0;
34680 this.highlightedSlice = undefined;
34681 this.timeGeometry._clearLabels();
34682 this.selection = new Selection();
34683 },
34684
34685 /**
34686 * initializes the timeplot elements with arrays of time objects
34687 * @param {TimeObject[][]} timeObjects an array of time objects from different (1-4) sets
34688 */
34689 initWidget : function(datasets) {
34690 this.datasets = datasets;
34691 var timeObjects = [];
34692 for (var i = 0; i < datasets.length; i++) {
34693 timeObjects.push(datasets[i].objects);
34694 }
34695 this.clearTimeplot();
34696 this.reset();
34697 for (var i = 0; i < this.timeplot._plots.length; i++) {
34698 this.timeplot._plots[i].dispose();
34699 }
34700 this.dataSources = new Array();
34701 this.plotInfos = new Array();
34702 this.eventSources = new Array();
34703 var granularity = 0;
34704 this.count = 0;
34705 for (var i = 0; i < timeObjects.length; i++) {
34706 if( i==0 || !this.options.timeMerge ){
34707 var eventSource = new Timeplot.DefaultEventSource();
34708 var dataSource = new Timeplot.ColumnSource(eventSource, 1);
34709 this.dataSources.push(dataSource);
34710 this.eventSources.push(eventSource);
34711 var c = GeoTemConfig.getColor(i);
34712 var plotInfo = Timeplot.createPlotInfo({
34713 id : "plot" + i,
34714 dataSource : dataSource,
34715 timeGeometry : this.timeGeometry,
34716 valueGeometry : this.valueGeometry,
34717 fillGradient : false,
34718 lineColor : 'rgba(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ', 1)',
34719 fillColor : 'rgba(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ', 0.3)',
34720 showValues : true
34721 });
34722 this.plotInfos.push(plotInfo);
34723 }
34724 for (var j = 0; j < timeObjects[i].length; j++) {
34725 var o = timeObjects[i][j];
34726 if (o.isTemporal) {
34727 var g = o.dates[this.options.timeIndex].granularity;
34728 if (g == null) {
34729 continue;
34730 } else if (g > granularity) {
34731 granularity = g;
34732 }
34733 this.count += o.weight;
34734 }
34735 }
34736 }
34737 this.timeGeometry._granularity = granularity;
34738 this.timeGeometry._clearLabels();
34739 this.timeplot.resetPlots(this.plotInfos);
34740 if (this.plotInfos.length == 0) {
34741 this.initLabels(this.timeplot.regularGrid());
34742 return;
34743 }
34744 this.timeGeometry.extendedDataSource = this.tds;
34745 this.tds.initialize(this.dataSources, this.eventSources, timeObjects, granularity, this.options.timeUnit, this.gui.timeplotDiv.offsetWidth);
34746 this.gui.setTimeUnitDropdown(this.tds.availableUnits);
34747 this.gui.timeUnitDropdown.setEntry(this.tds.getUnitIndex());
34748 var plots = this.timeplot._plots;
34749 for (var i = 0; i < plots.length; i++) {
34750 plots[i].pins = [];
34751 plots[i].style = this.style;
34752 for (var j = 0; j < this.tds.getSliceNumber(); j++) {
34753 plots[i].pins.push({
34754 height : 0,
34755 count : 0
34756 });
34757 }
34758 }
34759 /*
34760 var levels = Math.round( (this.tds.timeSlices.length-3)/2 );
34761 if( GeoTemConfig.timeZoom ){
34762 this.zoomSlider.setMaxAndLevels(levels,levels);
34763 }
34764 */
34765 this.timeplot.repaint();
34766 this.timeplot._resizeCanvas();
34767 // set maximum number of slider steps
34768 var slices = this.tds.timeSlices.length;
34769 var numSlices = Math.floor(slices / this.canvas.width * this.canvas.height + 0.5);
34770
34771 this.initLabels([]);
34772 this.initOverview();
34773 this.gui.updateTimeQuantity(this.count);
34774
34775 },
34776
34777 setTimeUnit : function(unit) {
34778 this.clearTimeplot();
34779 this.reset();
34780 this.tds.setTimeUnit(unit);
34781 var plots = this.timeplot._plots;
34782 for (var i = 0; i < plots.length; i++) {
34783 plots[i].pins = [];
34784 plots[i].style = this.style;
34785 for (var j = 0; j < this.tds.getSliceNumber(); j++) {
34786 plots[i].pins.push({
34787 height : 0,
34788 count : 0
34789 });
34790 }
34791 }
34792 this.initLabels([]);
34793 },
34794
34795 /**
34796 * initializes the timeplot for the Spatio Temporal Interface.
34797 * all elements (including their events) that are needed for user interaction are instantiated here, the slider element as well
34798 */
34799 initialize : function() {
34800
34801 this.status = 0;
34802 this.selection = new Selection();
34803 this.paused = true;
34804 this.dataSources = new Array();
34805 this.plotInfos = new Array();
34806 this.eventSources = new Array();
34807 this.timeGeometry = new Timeplot.DefaultTimeGeometry({
34808 gridColor : "#000000",
34809 axisLabelsPlacement : "top"
34810 });
34811 this.style = 'graph';
34812 this.timeGeometry._hideLabels = true;
34813 this.timeGeometry._granularity = 0;
34814 this.valueGeometry = new Timeplot.LogarithmicValueGeometry({
34815 min : 0
34816 });
34817 this.valueGeometry.actLinear();
34818
34819 var plot = this;
34820
34821 this.timeplot = Timeplot.create(this.gui.timeplotDiv, this.plotInfos);
34822 this.tds = new TimeDataSource(this.options);
34823
34824 this.canvas = this.timeplot.getCanvas();
34825
34826 this.leftFlagPole = this.timeplot.putDiv("leftflagpole", "timeplot-dayflag-pole");
34827 this.rightFlagPole = this.timeplot.putDiv("rightflagpole", "timeplot-dayflag-pole");
34828 SimileAjax.Graphics.setOpacity(this.leftFlagPole, 50);
34829 SimileAjax.Graphics.setOpacity(this.rightFlagPole, 50);
34830
34831 this.rangeBox = this.timeplot.putDiv("rangebox", "range-box");
34832 this.rangeBox.style.backgroundColor = plot.options.rangeBoxColor;
34833 this.rangeBox.style.border = plot.options.rangeBorder;
34834
34835 this.leftHandle = document.createElement("div");
34836 this.rightHandle = document.createElement("div");
34837 this.gui.plotWindow.appendChild(this.leftHandle);
34838 this.gui.plotWindow.appendChild(this.rightHandle);
34839 this.leftHandle.title = GeoTemConfig.getString('leftHandle');
34840 this.rightHandle.title = GeoTemConfig.getString('rightHandle');
34841
34842 this.leftHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "leftHandle.png" + ")";
34843 this.leftHandle.setAttribute('class', 'plotHandle plotHandleIcon');
34844 this.rightHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "rightHandle.png" + ")";
34845 this.rightHandle.setAttribute('class', 'plotHandle plotHandleIcon');
34846
34847 this.poles = this.timeplot.putDiv("poles", "pole");
34848 this.timeplot.placeDiv(this.poles, {
34849 left : 0,
34850 bottom : 0,
34851 width : this.canvas.width,
34852 height : this.canvas.height,
34853 display : "block"
34854 });
34855 this.poles.appendChild(document.createElement("canvas"));
34856
34857 this.filterBar = new FilterBar(this, this.gui.filterOptions);
34858
34859 var plot = this;
34860
34861 this.dragButton = document.createElement("div");
34862 this.dragButton.title = GeoTemConfig.getString('dragTimeRange');
34863 this.cancelButton = document.createElement("div");
34864 this.cancelButton.title = GeoTemConfig.getString('clearSelection');
34865 this.cancelButton.onclick = function() {
34866 plot.deselection();
34867 }
34868
34869 this.toolbar = document.createElement("div");
34870 this.toolbar.setAttribute('class', 'plotToolbar');
34871 this.toolbar.style.borderTop = plot.options.rangeBorder;
34872 this.toolbar.style.textAlign = "center";
34873 this.gui.plotWindow.appendChild(this.toolbar);
34874
34875 this.toolbarAbsoluteDiv = document.createElement("div");
34876 this.toolbarAbsoluteDiv.setAttribute('class', 'absoluteToolbar');
34877 this.toolbar.appendChild(this.toolbarAbsoluteDiv);
34878
34879 this.dragButton.setAttribute('class', 'dragTimeRangeAlt');
34880 this.dragButton.style.backgroundImage = "url(" + GeoTemConfig.path + "drag.png" + ")";
34881 // this.zoomButton.setAttribute('class','zoomRangeAlt');
34882 this.cancelButton.setAttribute('class', 'cancelRangeAlt');
34883 this.toolbarAbsoluteDiv.appendChild(this.dragButton);
34884 this.toolbarAbsoluteDiv.style.width = this.dragButton.offsetWidth + "px";
34885 // this.gui.plotWindow.appendChild(this.zoomButton);
34886 this.gui.plotWindow.appendChild(this.cancelButton);
34887
34888 this.overview = document.createElement("div");
34889 this.overview.setAttribute('class', 'timeOverview');
34890 this.gui.plotWindow.appendChild(this.overview);
34891
34892 var mousedown = false;
34893 this.shift = function(shift) {
34894 if (!mousedown) {
34895 return;
34896 }
34897 if (plot.tds.setShift(shift)) {
34898 plot.redrawPlot();
34899 }
34900 setTimeout(function() {
34901 plot.shift(shift);
34902 }, 200);
34903 }
34904 var shiftPressed = function(shift) {
34905 mousedown = true;
34906 document.onmouseup = function() {
34907 mousedown = false;
34908 document.onmouseup = null;
34909 }
34910 plot.shift(shift);
34911 }
34912
34913 this.shiftLeft = document.createElement("div");
34914 this.shiftLeft.setAttribute('class', 'shiftLeft');
34915 this.gui.plotWindow.appendChild(this.shiftLeft);
34916 this.shiftLeft.onmousedown = function() {
34917 shiftPressed(1);
34918 }
34919
34920 this.shiftRight = document.createElement("div");
34921 this.shiftRight.setAttribute('class', 'shiftRight');
34922 this.gui.plotWindow.appendChild(this.shiftRight);
34923 this.shiftRight.onmousedown = function() {
34924 shiftPressed(-1);
34925 }
34926
34927 this.plotLabels = document.createElement("div");
34928 this.plotLabels.setAttribute('class', 'plotLabels');
34929 this.gui.plotWindow.appendChild(this.plotLabels);
34930
34931 this.initLabels(this.timeplot.regularGrid());
34932
34933 //Finds the time corresponding to the position x on the timeplot
34934 var getCorrelatedTime = function(x) {
34935 if (x >= plot.canvas.width)
34936 x = plot.canvas.width;
34937 if (isNaN(x) || x < 0)
34938 x = 0;
34939 var t = plot.timeGeometry.fromScreen(x);
34940 if (t == 0)
34941 return;
34942 return plot.dataSources[0].getClosestValidTime(t);
34943 }
34944 //Finds the position corresponding to the time t on the timeplot
34945 var getCorrelatedPosition = function(t) {
34946 var x = plot.timeGeometry.toScreen(t);
34947 if (x >= plot.canvas.width)
34948 x = plot.canvas.width;
34949 if (isNaN(x) || x < 0)
34950 x = 0;
34951 return x;
34952 }
34953 //Maps the 2 positions in the right order to left and right bound of the chosen timeRange
34954 var mapPositions = function(pos1, pos2) {
34955 if (pos1 > pos2) {
34956 plot.leftFlagPos = pos2;
34957 plot.rightFlagPos = pos1;
34958 } else {
34959 plot.leftFlagPos = pos1;
34960 plot.rightFlagPos = pos2;
34961 }
34962 plot.leftFlagTime = plot.dataSources[0].getClosestValidTime(plot.timeGeometry.fromScreen(plot.leftFlagPos));
34963 plot.rightFlagTime = plot.dataSources[0].getClosestValidTime(plot.timeGeometry.fromScreen(plot.rightFlagPos));
34964 }
34965 //Sets the divs corresponding to the actual chosen timeRange
34966 var setRangeDivs = function() {
34967 plot.leftFlagPole.style.visibility = "visible";
34968 plot.rightFlagPole.style.visibility = "visible";
34969 plot.rangeBox.style.visibility = "visible";
34970 plot.timeplot.placeDiv(plot.leftFlagPole, {
34971 left : plot.leftFlagPos,
34972 bottom : 0,
34973 height : plot.canvas.height,
34974 display : "block"
34975 });
34976 plot.timeplot.placeDiv(plot.rightFlagPole, {
34977 left : plot.rightFlagPos,
34978 bottom : 0,
34979 height : plot.canvas.height,
34980 display : "block"
34981 });
34982 var boxWidth = plot.rightFlagPos - plot.leftFlagPos;
34983 if (plot.popup) {
34984 plot.popupClickDiv.style.visibility = "visible";
34985 plot.timeplot.placeDiv(plot.popupClickDiv, {
34986 left : plot.leftFlagPos,
34987 width : boxWidth + 1,
34988 height : plot.canvas.height,
34989 display : "block"
34990 });
34991 }
34992 plot.timeplot.placeDiv(plot.rangeBox, {
34993 left : plot.leftFlagPos,
34994 width : boxWidth + 1,
34995 height : plot.canvas.height,
34996 display : "block"
34997 });
34998 var plots = plot.timeplot._plots;
34999 for ( i = 0; i < plots.length; i++) {
35000 plots[i].fullOpacityPlot(plot.leftFlagTime, plot.rightFlagTime, plot.leftFlagPos, plot.rightFlagPos, GeoTemConfig.getColor(i));
35001 plots[i].opacityPlot.style.visibility = "visible";
35002 }
35003 var unit = plot.tds.unit;
35004
35005 var top = plot.gui.plotContainer.offsetTop;
35006 var left = plot.gui.plotContainer.offsetLeft;
35007 var leftPos = plot.leftFlagPole.offsetLeft + plot.timeplot.getElement().offsetLeft;
35008 var rightPos = plot.rightFlagPole.offsetLeft + plot.timeplot.getElement().offsetLeft;
35009 var rW = rightPos - leftPos;
35010 var pW = plot.canvas.width;
35011 var pL = plot.timeplot.getElement().offsetLeft;
35012
35013 var handleTop = top + Math.floor(plot.gui.timeplotDiv.offsetHeight / 2 - plot.leftHandle.offsetHeight / 2);
35014 plot.leftHandle.style.visibility = "visible";
35015 plot.rightHandle.style.visibility = "visible";
35016 plot.leftHandle.style.left = (leftPos - plot.leftHandle.offsetWidth / 2) + "px";
35017 plot.rightHandle.style.left = (rightPos - plot.rightHandle.offsetWidth + 1 + plot.rightHandle.offsetWidth / 2) + "px";
35018 plot.leftHandle.style.top = handleTop + "px";
35019 plot.rightHandle.style.top = handleTop + "px";
35020 if (rightPos == leftPos) {
35021 plot.rightHandle.style.visibility = "hidden";
35022 plot.leftHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "mergedHandle.png" + ")";
35023 } else {
35024 plot.leftHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "leftHandle.png" + ")";
35025 }
35026 plot.cancelButton.style.visibility = "visible";
35027 plot.cancelButton.style.top = top + "px";
35028
35029 if (rW > plot.cancelButton.offsetWidth) {
35030 plot.cancelButton.style.left = (left + rightPos - plot.cancelButton.offsetWidth) + "px";
35031 } else {
35032 plot.cancelButton.style.left = (left + rightPos) + "px";
35033 }
35034 var tW = plot.toolbarAbsoluteDiv.offsetWidth;
35035 if (rW >= tW) {
35036 plot.toolbar.style.left = leftPos + "px";
35037 plot.toolbar.style.width = (rW + 1) + "px";
35038 plot.toolbarAbsoluteDiv.style.left = ((rW - tW) / 2) + "px";
35039 } else {
35040 plot.toolbar.style.left = (pL + plot.leftFlagPos * (pW - tW) / (pW - rW)) + "px";
35041 plot.toolbar.style.width = (tW + 2) + "px";
35042 plot.toolbarAbsoluteDiv.style.left = "0px";
35043 }
35044 plot.toolbar.style.top = (top + plot.timeplot.getElement().offsetHeight) + "px";
35045 plot.toolbar.style.visibility = "visible";
35046 plot.toolbarAbsoluteDiv.style.visibility = "visible";
35047
35048 }
35049 var getAbsoluteLeft = function(div) {
35050 var left = 0;
35051 while (div) {
35052 left += div.offsetLeft;
35053 div = div.offsetParent;
35054 }
35055 return left;
35056 }
35057 var timeplotLeft = getAbsoluteLeft(plot.timeplot.getElement());
35058
35059 var checkPolesForStyle = function(x) {
35060 if (plot.style == 'bars' && plot.leftFlagTime == plot.rightFlagTime) {
35061 var index = plot.tds.getSliceIndex(plot.leftFlagTime);
35062 var time1 = plot.leftFlagTime;
35063 var pos1 = plot.leftFlagPos;
35064 var time2, pos2;
35065 if (index == 0) {
35066 time2 = plot.tds.getSliceTime(index + 1);
35067 } else if (index == plot.tds.getSliceNumber() - 1) {
35068 time2 = plot.tds.getSliceTime(index - 1);
35069 } else {
35070 if (x < plot.leftFlagPos) {
35071 time2 = plot.tds.getSliceTime(index - 1);
35072 } else {
35073 time2 = plot.tds.getSliceTime(index + 1);
35074 }
35075 }
35076 pos2 = plot.timeGeometry.toScreen(time2);
35077 mapPositions(pos1, pos2, time1, time2);
35078 }
35079 }
35080 var startX, startY, multiplier;
35081
35082 // mousemove function that causes moving selection of objects and toolbar divs
35083 var moveToolbar = function(start, actual) {
35084 var pixelShift = actual - start;
35085 if (plot.status == 2) {
35086 var newTime = getCorrelatedTime(startX + pixelShift);
35087 if (newTime == plot.mouseTempTime) {
35088 return;
35089 }
35090 plot.mouseTempTime = newTime;
35091 plot.mouseTempPos = plot.timeGeometry.toScreen(plot.mouseTempTime);
35092 mapPositions(plot.mouseDownPos, plot.mouseTempPos);
35093 } else if (plot.status == 3) {
35094 pixelShift *= multiplier;
35095 var plotPos = actual - timeplotLeft;
35096 if (plotPos <= plot.canvas.width / 2) {
35097 var newTime = getCorrelatedTime(startX + pixelShift);
35098 if (newTime == plot.leftFlagTime) {
35099 return;
35100 }
35101 plot.leftFlagTime = newTime;
35102 var diff = plot.leftFlagPos;
35103 plot.leftFlagPos = plot.timeGeometry.toScreen(plot.leftFlagTime);
35104 diff -= plot.leftFlagPos;
35105 plot.rightFlagTime = getCorrelatedTime(plot.rightFlagPos - diff);
35106 plot.rightFlagPos = plot.timeGeometry.toScreen(plot.rightFlagTime);
35107 } else {
35108 var newTime = getCorrelatedTime(startY + pixelShift);
35109 if (newTime == plot.rightFlagTime) {
35110 return;
35111 }
35112 plot.rightFlagTime = newTime;
35113 var diff = plot.rightFlagPos;
35114 plot.rightFlagPos = plot.timeGeometry.toScreen(plot.rightFlagTime);
35115 diff -= plot.rightFlagPos;
35116 plot.leftFlagTime = getCorrelatedTime(plot.leftFlagPos - diff);
35117 plot.leftFlagPos = plot.timeGeometry.toScreen(plot.leftFlagTime);
35118 }
35119 }
35120 checkPolesForStyle(actual - timeplotLeft);
35121 setRangeDivs();
35122 plot.timeSelection();
35123 }
35124 // fakes user interaction mouse move
35125 var playIt = function(start, actual, reset) {
35126 if (!plot.paused) {
35127 var pixel = plot.canvas.width / (plot.tds.timeSlices.length - 1 ) / 5;
35128 var wait = 20 * pixel;
35129 if (reset) {
35130 actual = 0;
35131 }
35132 moveToolbar(start, actual);
35133 if (plot.rightFlagPos >= plot.canvas.width) {
35134 reset = true;
35135 wait = 1000;
35136 } else {
35137 reset = false;
35138 }
35139 setTimeout(function() {
35140 playIt(start, actual + pixel, reset)
35141 }, wait);
35142 }
35143 }
35144 var setMultiplier = function() {
35145 var rangeWidth = plot.rightFlagPos - plot.leftFlagPos;
35146 var toolbarWidth = plot.toolbarAbsoluteDiv.offsetWidth;
35147 var plotWidth = plot.canvas.width;
35148 if (rangeWidth < toolbarWidth) {
35149 multiplier = (plotWidth - rangeWidth) / (plotWidth - toolbarWidth);
35150 } else {
35151 multiplier = 1;
35152 }
35153 }
35154 /**
35155 * starts the animation
35156 */
35157 this.play = function() {
35158 if (this.leftFlagPos == null) {
35159 return;
35160 }
35161 plot.paused = false;
35162 plot.gui.updateAnimationButtons(2);
35163 plot.status = 3;
35164 setMultiplier();
35165 startX = plot.leftFlagPos;
35166 startY = plot.rightFlagPos;
35167 var position = Math.round(plot.leftFlagPos);
35168 playIt(position, position + 1, false);
35169 }
35170 /**
35171 * stops the animation
35172 */
35173 this.stop = function() {
35174 plot.paused = true;
35175 plot.status = 0;
35176 plot.gui.updateAnimationButtons(1);
35177 }
35178 // triggers the mousemove function to move the range and toolbar
35179 var toolbarEvent = function(evt) {
35180 var left = GeoTemConfig.getMousePosition(evt).left;
35181 document.onmousemove = function(evt) {
35182 moveToolbar(left, GeoTemConfig.getMousePosition(evt).left);
35183 if (plot.popup) {
35184 plot.popup.reset();
35185 }
35186 }
35187 }
35188 var initializeLeft = function() {
35189 plot.mouseDownTime = plot.rightFlagTime;
35190 plot.mouseTempTime = plot.leftFlagTime;
35191 plot.mouseDownPos = plot.timeGeometry.toScreen(plot.mouseDownTime);
35192 startX = plot.leftFlagPos;
35193 }
35194 var initializeRight = function() {
35195 plot.mouseDownTime = plot.leftFlagTime;
35196 plot.mouseTempTime = plot.rightFlagTime;
35197 plot.mouseDownPos = plot.timeGeometry.toScreen(plot.mouseDownTime);
35198 startX = plot.rightFlagPos;
35199 }
35200 var initializeDrag = function() {
35201 startX = plot.leftFlagPos;
35202 startY = plot.rightFlagPos;
35203 setMultiplier();
35204 }
35205 var checkBorders = function() {
35206 if (plot.style == 'bars' && plot.mouseUpTime == plot.mouseDownTime) {
35207 var index = plot.tds.getSliceIndex(plot.mouseUpTime);
35208 if (index == 0) {
35209 plot.mouseUpTime = plot.tds.getSliceTime(index + 1);
35210 } else if (index == plot.tds.getSliceNumber() - 1) {
35211 plot.mouseUpTime = plot.tds.getSliceTime(index - 1);
35212 } else {
35213 if (plot.x < plot.leftFlagPos) {
35214 plot.mouseUpTime = plot.tds.getSliceTime(index - 1);
35215 } else {
35216 plot.mouseUpTime = plot.tds.getSliceTime(index + 1);
35217 }
35218 }
35219 }
35220 }
35221 // handles mousedown on left handle
35222 this.leftHandle.onmousedown = function(evt) {
35223 if (plot.status != 2) {
35224
35225 initializeLeft();
35226 plot.status = 2;
35227 toolbarEvent(evt);
35228 document.onmouseup = function() {
35229 document.onmousemove = null;
35230 document.onmouseup = null;
35231 plot.stop();
35232 }
35233 }
35234 }
35235 // handles mousedown on right handle
35236 this.rightHandle.onmousedown = function(evt) {
35237 if (plot.status != 2) {
35238 initializeRight();
35239 plot.status = 2;
35240 toolbarEvent(evt);
35241 document.onmouseup = function() {
35242 document.onmousemove = null;
35243 document.onmouseup = null;
35244 plot.stop();
35245 }
35246 }
35247 }
35248 // handles mousedown on drag button
35249 this.dragButton.onmousedown = function(evt) {
35250 if (plot.status != 3) {
35251 plot.status = 3;
35252 initializeDrag();
35253 toolbarEvent(evt);
35254 document.onmouseup = function() {
35255 document.onmousemove = null;
35256 document.onmouseup = null;
35257 plot.stop();
35258 }
35259 }
35260 }
35261 // handles mousedown-Event on timeplot
35262 var mouseDownHandler = function(elmt, evt, target) {
35263 if (plot.dataSources.length > 0) {
35264
35265 plot.x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
35266 if (plot.status == 0) {
35267 var time = getCorrelatedTime(plot.x);
35268 if (plot.leftFlagPos != null && plot.popup && time >= plot.leftFlagTime && time <= plot.rightFlagTime) {
35269 var x = plot.leftFlagPos + (plot.rightFlagPos - plot.leftFlagPos) / 2;
35270 var elements = [];
35271 for (var i = 0; i < plot.dataSources.length; i++) {
35272 elements.push([]);
35273 }
35274 for (var i = 0; i < plot.selectedObjects.length; i++) {
35275 if (plot.selectedObjects[i].value == 1) {
35276 for (var j = 0; j < plot.selectedObjects[i].objects.length; j++) {
35277 elements[j] = elements[j].concat(plot.selectedObjects[i].objects[j]);
35278 }
35279 }
35280 }
35281 var labels = [];
35282 for (var i = 0; i < elements.length; i++) {
35283 if (elements[i].length == 0) {
35284 continue;
35285 }
35286 var c = GeoTemConfig.getColor(i);
35287 var color = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
35288 var div = document.createElement("div");
35289 div.setAttribute('class', 'tagCloudItem');
35290 div.style.color = color;
35291 var label = {
35292 div : div,
35293 elements : elements[i]
35294 };
35295 var weight = 0;
35296 for (j in elements[i] ) {
35297 weight += elements[i][j].weight;
35298 }
35299 var fs = 2 * weight / 1000;
35300 if (fs > 2) {
35301 fs = 2;
35302 }
35303 div.style.fontSize = (1 + fs) + "em";
35304 div.style.textShadow = "0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em " + c.hex;
35305 if (weight == 1) {
35306 div.innerHTML = weight + " object";
35307 } else {
35308 div.innerHTML = weight + " objects";
35309 }
35310 var appendMouseFunctions = function(label, div, color) {
35311 div.onclick = function() {
35312 plot.popup.showLabelContent(label);
35313 div.style.textShadow = "0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em " + color;
35314 }
35315 div.onmouseover = function() {
35316 div.style.textShadow = "0 -1px " + color + ", 1px 0 " + color + ", 0 1px " + color + ", -1px 0 " + color;
35317 }
35318 div.onmouseout = function() {
35319 div.style.textShadow = "0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em black, 0 0 0.4em " + color;
35320 }
35321 }
35322 appendMouseFunctions(label, div, c.hex);
35323 labels.push(label);
35324 }
35325 if (labels.length > 0) {
35326 plot.popup.createPopup(x + 20, 0, labels);
35327 }
35328 } else {
35329 plot.deselection();
35330 plot.status = 1;
35331 plot.mouseDownTime = time;
35332 plot.mouseTempTime = plot.mouseDownTime;
35333 plot.mouseDownPos = plot.timeGeometry.toScreen(plot.mouseDownTime);
35334 mapPositions(plot.mouseDownPos, plot.mouseDownPos, plot.mouseDownTime, plot.mouseDownTime);
35335 // handles mouseup-Event on timeplot
35336 document.onmouseup = function() {
35337 if (plot.status == 1) {
35338 plot.mouseUpTime = plot.mouseTempTime;
35339 plot.mouseUpPos = plot.timeGeometry.toScreen(plot.mouseUpTime);
35340 mapPositions(plot.mouseDownPos, plot.mouseUpPos, plot.mouseDownTime, plot.mouseUpTime);
35341 checkPolesForStyle(plot.x);
35342 setRangeDivs();
35343 plot.timeSelection();
35344 plot.gui.updateAnimationButtons(1);
35345 document.onmouseup = null;
35346 plot.status = 0;
35347 }
35348 }
35349 }
35350 }
35351 }
35352 }
35353 // handles mousemove-Event on timeplot
35354 var mouseMoveHandler = function(elmt, evt, target) {
35355 if (plot.dataSources.length > 0) {
35356 plot.x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
35357 if (plot.status == 1) {
35358 plot.mouseTempTime = getCorrelatedTime(plot.x);
35359 plot.mouseTempPos = plot.timeGeometry.toScreen(plot.mouseTempTime);
35360 mapPositions(plot.mouseDownPos, plot.mouseTempPos, plot.mouseDownTime, plot.mouseTempTime);
35361 checkPolesForStyle(plot.x);
35362 setRangeDivs();
35363 }
35364 }
35365 }
35366 // handles mouseout-Event on timeplot
35367 var mouseOutHandler = function(elmt, evt, target) {
35368 if (plot.dataSources.length > 0) {
35369 var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
35370 var y = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).y);
35371 if (x > plot.canvas.width - 2 || isNaN(x) || x < 2) {
35372 plot.timeHighlight(true);
35373 plot.highlightedSlice = undefined;
35374 } else if (y > plot.canvas.height - 2 || isNaN(y) || y < 2) {
35375 plot.timeHighlight(true);
35376 plot.highlightedSlice = undefined;
35377 }
35378 }
35379 }
35380 // handles mouse(h)over-Event on timeplot
35381 var mouseHoverHandler = function(elmt, evt, target) {
35382 if (plot.dataSources.length > 0) {
35383 var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
35384 var time = getCorrelatedTime(x);
35385 if (time == undefined) {
35386 return;
35387 }
35388 var highlightSlice;
35389 var slices = plot.tds.timeSlices;
35390 var index = plot.tds.getSliceIndex(time);
35391 if (plot.style == 'graph') {
35392 highlightSlice = slices[index];
35393 }
35394 if (plot.style == 'bars') {
35395 var pos = plot.timeGeometry.toScreen(time);
35396 if (x < pos && index > 0) {
35397 highlightSlice = slices[index - 1];
35398 } else {
35399 highlightSlice = slices[index];
35400 }
35401 }
35402 if (plot.highlightedSlice == undefined || plot.highlightedSlice != highlightSlice) {
35403 plot.highlightedSlice = highlightSlice;
35404 plot.timeHighlight(false);
35405 }
35406 }
35407 }
35408
35409 this.redrawPlot = function() {
35410 plot.clearTimeplot();
35411 plot.tds.reset(this.timeGeometry);
35412 plot.timeplot._prepareCanvas();
35413 plot.timeplot.repaint();
35414 if (plot.leftFlagPos != null) {
35415 plot.leftFlagPos = getCorrelatedPosition(plot.leftFlagTime);
35416 plot.rightFlagPos = getCorrelatedPosition(plot.rightFlagTime);
35417 setRangeDivs();
35418 } else {
35419 plot.displayOverlay();
35420 }
35421 plot.initLabels([]);
35422 plot.updateOverview();
35423 }
35424
35425 this.resetOpacityPlots = function() {
35426 var plots = plot.timeplot._plots;
35427 for ( var i = 0; i < plots.length; i++) {
35428 plots[i]._opacityCanvas.width = this.canvas.width;
35429 plots[i]._opacityCanvas.height = this.canvas.height;
35430 if( plot.leftFlagTime != null ){
35431 plots[i].fullOpacityPlot(plot.leftFlagTime, plot.rightFlagTime, plot.leftFlagPos, plot.rightFlagPos, GeoTemConfig.getColor(i));
35432 }
35433 }
35434 }
35435
35436 /**
35437 * handles zoom of the timeplot
35438 * @param {int} delta the change of zoom
35439 * @param {Date} time a time that corresponds to a slice, that was clicked
35440 */
35441 /*
35442 this.zoom = function(delta,time){
35443 if( this.eventSources.length == 0 ){
35444 if( GeoTemConfig.timeZoom ){
35445 this.zoomSlider.setValue(0);
35446 }
35447 return false;
35448 }
35449 if( time == null ){
35450 time = getCorrelatedTime(this.canvas.width/2);
35451 }
35452 if( this.tds.setZoom(delta,time,this.leftFlagTime,this.rightFlagTime) ){
35453 this.redrawPlot();
35454 }
35455 if( GeoTemConfig.timeZoom ){
35456 this.zoomSlider.setValue(this.tds.getZoom());
35457 }
35458 return true;
35459 }
35460 */
35461
35462 // handles mousewheel event on the timeplot
35463 var mouseWheelHandler = function(elmt, evt, target) {
35464 if (evt.preventDefault) {
35465 evt.preventDefault();
35466 }
35467 if (plot.dataSources.length == 0) {
35468 return;
35469 }
35470 var delta = 0;
35471 if (!evt)
35472 evt = window.event;
35473 if (evt.wheelDelta) {
35474 delta = evt.wheelDelta / 120;
35475 if (window.opera)
35476 delta = -delta;
35477 } else if (evt.detail) {
35478 delta = -evt.detail / 3;
35479 }
35480 if (delta) {
35481 var x = Math.round(SimileAjax.DOM.getEventRelativeCoordinates(evt, plot.canvas).x);
35482 var time = getCorrelatedTime(x);
35483 plot.zoom(delta, time);
35484 }
35485 }
35486 var timeplotElement = this.timeplot.getElement();
35487 SimileAjax.DOM.registerEvent(timeplotElement, "mousedown", mouseDownHandler);
35488 SimileAjax.DOM.registerEvent(timeplotElement, "mousemove", mouseMoveHandler);
35489 SimileAjax.DOM.registerEvent(timeplotElement, "mousemove", mouseHoverHandler);
35490 SimileAjax.DOM.registerEvent(timeplotElement, "mouseout", mouseOutHandler);
35491 if (GeoTemConfig.mouseWheelZoom) {
35492 //SimileAjax.DOM.registerEvent(timeplotElement, "mousewheel", mouseWheelHandler);
35493 }
35494
35495 this.gui.setHeight();
35496
35497 },
35498
35499 resetOverlay : function() {
35500 this.poles.style.visibility = "hidden";
35501 var plots = this.timeplot._plots;
35502 for (var i = 0; i < plots.length; i++) {
35503 for (var j = 0; j < plots[i].pins.length; j++) {
35504 plots[i].pins[j] = {
35505 height : 0,
35506 count : 0
35507 };
35508 }
35509 }
35510 },
35511
35512 /**
35513 * resets the timeplot to non selection status
35514 */
35515 reset : function() {
35516
35517 this.leftFlagPole.style.visibility = "hidden";
35518 this.rightFlagPole.style.visibility = "hidden";
35519 this.rangeBox.style.visibility = "hidden";
35520 this.leftHandle.style.visibility = "hidden";
35521 this.rightHandle.style.visibility = "hidden";
35522 this.toolbar.style.visibility = "hidden";
35523 this.toolbarAbsoluteDiv.style.visibility = "hidden";
35524 this.cancelButton.style.visibility = "hidden";
35525
35526 var plots = this.timeplot._plots;
35527 for (var i = 0; i < plots.length; i++) {
35528 plots[i].opacityPlot.style.visibility = "hidden";
35529 }
35530 this.resetOverlay();
35531 this.filterBar.reset(false);
35532
35533 var slices = this.tds.timeSlices;
35534 if (slices != undefined) {
35535 for (var i = 0; i < slices.length; i++) {
35536 slices[i].reset();
35537 }
35538 }
35539
35540 this.status = 0;
35541 this.stop();
35542 this.gui.updateAnimationButtons(0);
35543
35544 this.leftFlagPos = null;
35545 this.leftFlagTime = null;
35546 this.rightFlagPos = null;
35547 this.rightFlagTime = null;
35548
35549 this.mouseDownTime = null;
35550 this.mouseUpTime = null;
35551 this.mouseTempTime = null;
35552
35553 this.mouseDownPos = null;
35554 this.mouseUpPos = null;
35555 this.mouseTempPos = null;
35556
35557 if (this.popup) {
35558 this.popup.reset();
35559 this.popupClickDiv.style.visibility = "hidden";
35560 }
35561
35562 },
35563
35564 /**
35565 * sets a pole on the timeplot
35566 * @param {Date} time the time of the specific timeslice
35567 * @param {int[]} the number of selected elements per dataset
35568 */
35569 displayOverlay : function() {
35570 this.poles.style.visibility = "visible";
35571 var cv = this.poles.getElementsByTagName("canvas")[0];
35572 cv.width = this.canvas.width;
35573 cv.height = this.canvas.height;
35574 if (!cv.getContext && G_vmlCanvasManager) {
35575 cv = G_vmlCanvasManager.initElement(cv);
35576 }
35577 var ctx = cv.getContext('2d');
35578 ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
35579 var plots = this.timeplot._plots;
35580 var slices = this.tds.timeSlices;
35581 for (var i = 0; i < slices.length; i++) {
35582 if (this.style == 'bars' && i + 1 == slices.length) {
35583 return;
35584 }
35585 if (slices[i].overlay() == 0) {
35586 continue;
35587 }
35588 var projStacks = slices[i].projStacks;
35589 var time = slices[i].date;
35590 var pos;
35591 if (this.style == 'graph') {
35592 pos = this.timeGeometry.toScreen(time);
35593 } else if (this.style == 'bars') {
35594 var x1 = this.timeGeometry.toScreen(time);
35595 var x2 = this.timeGeometry.toScreen(slices[i + 1].date);
35596 pos = (x1 + x2 ) / 2;
35597 }
35598 var heights = [];
35599 var h = 0;
35600 for (var j = 0; j < projStacks.length; j++) {
35601 var data = plots[j]._dataSource.getData();
35602 for (var k = 0; k < data.times.length; k++) {
35603 if (data.times[k].getTime() == time.getTime()) {
35604 var height = plots[j]._valueGeometry.toScreen(plots[j]._dataSource.getData().values[k]) * projStacks[j].overlay / projStacks[j].value;
35605 heights.push(height);
35606 plots[j].pins[i] = {
35607 height : height,
35608 count : projStacks[j].overlay
35609 };
35610 if (height > h) {
35611 h = height;
35612 }
35613 break;
35614 }
35615 }
35616 }
35617 ctx.fillStyle = "rgb(102,102,102)";
35618 ctx.beginPath();
35619 ctx.rect(pos - 1, this.canvas.height - h, 2, h);
35620 ctx.fill();
35621 for (var j = 0; j < heights.length; j++) {
35622 if (heights[j] > 0) {
35623 var color = GeoTemConfig.getColor(j);
35624 ctx.fillStyle = "rgba(" + color.r1 + "," + color.g1 + "," + color.b1 + ",0.6)";
35625 ctx.beginPath();
35626 ctx.arc(pos, this.canvas.height - heights[j], 2.5, 0, Math.PI * 2, true);
35627 ctx.closePath();
35628 ctx.fill();
35629 }
35630 }
35631 }
35632 },
35633
35634 /**
35635 * updates the timeplot by displaying place poles, after a selection had been executed in another widget
35636 */
35637 highlightChanged : function(timeObjects) {
35638 if( !GeoTemConfig.highlightEvents ){
35639 return;
35640 }
35641 this.resetOverlay();
35642 if (this.selection.valid()) {
35643 if (!this.selection.equal(this)) {
35644 this.tds.setOverlay(GeoTemConfig.mergeObjects(timeObjects, this.selection.getObjects(this)));
35645 } else {
35646 this.tds.setOverlay(timeObjects);
35647 }
35648 } else {
35649 this.tds.setOverlay(timeObjects);
35650 }
35651 this.displayOverlay();
35652 },
35653
35654 /**
35655 * updates the timeplot by displaying place poles, after a selection had been executed in another widget
35656 */
35657 selectionChanged : function(selection) {
35658 if( !GeoTemConfig.selectionEvents ){
35659 return;
35660 }
35661 this.reset();
35662 this.selection = selection;
35663 this.tds.setOverlay(selection.objects);
35664 this.displayOverlay();
35665 },
35666
35667 /**
35668 * returns the approximate left position of a slice inside the overview representation
35669 * @param {Date} time time of the slice
35670 */
35671 getOverviewLeft : function(time) {
35672 var w = this.overview.offsetWidth;
35673 var s = this.tds.earliest().getTime();
35674 var e = this.tds.latest().getTime();
35675 var t = time.getTime();
35676 return Math.round(w * (t - s) / (e - s));
35677 },
35678
35679 /**
35680 * visualizes the overview div (shows viewable part of zoomed timeplot)
35681 */
35682 initOverview : function() {
35683 var labels = this.timeGeometry._grid;
35684 if (labels.length == 0) {
35685 var plot = this;
35686 setTimeout(function() {
35687 plot.initOverview();
35688 }, 10);
35689 return;
35690 }
35691
35692 this.overview.style.width = this.canvas.width + "px";
35693 var left = this.gui.timeplotDiv.offsetLeft;
35694 this.overview.innerHTML = "";
35695 this.overview.style.left = left + "px";
35696
35697 this.overviewRange = document.createElement("div");
35698 this.overviewRange.setAttribute('class', 'overviewRange');
35699 this.overview.appendChild(this.overviewRange);
35700
35701 for (var i = 0; i < labels.length; i++) {
35702 var label = document.createElement("div");
35703 label.setAttribute('class', 'overviewLabel');
35704 label.innerHTML = labels[i].label;
35705 label.style.left = Math.floor(labels[i].x) + "px";
35706 this.overview.appendChild(label);
35707 }
35708
35709 this.updateOverview();
35710 },
35711
35712 /**
35713 * visualizes the labels of the timeplot
35714 */
35715 initLabels : function(labels) {
35716 if (labels.length == 0) {
35717 labels = this.timeGeometry._grid;
35718 if (labels.length == 0) {
35719 var plot = this;
35720 setTimeout(function() {
35721 plot.initLabels([]);
35722 }, 10);
35723 return;
35724 }
35725 }
35726 this.plotLabels.style.width = this.canvas.width + "px";
35727 var left = this.gui.timeplotDiv.offsetLeft;
35728 this.plotLabels.style.left = left + "px";
35729 this.plotLabels.innerHTML = "";
35730 for (var i = 0; i < labels.length; i++) {
35731 var label = document.createElement("div");
35732 label.setAttribute('class', 'plotLabel');
35733 label.innerHTML = labels[i].label;
35734 label.style.left = Math.floor(labels[i].x) + "px";
35735 this.plotLabels.appendChild(label);
35736 }
35737 },
35738
35739 /**
35740 * updates the overview div
35741 */
35742 updateOverview : function() {
35743 if (this.tds.getZoom() > 0) {
35744 this.plotLabels.style.visibility = "hidden";
35745 this.timeGeometry._hideLabels = false;
35746 this.overview.style.visibility = "visible";
35747 this.shiftLeft.style.visibility = "visible";
35748 this.shiftRight.style.visibility = "visible";
35749 var left = this.getOverviewLeft(this.tds.timeSlices[this.tds.leftSlice].date);
35750 var right = this.getOverviewLeft(this.tds.timeSlices[this.tds.rightSlice].date);
35751 this.overviewRange.style.left = left + "px";
35752 this.overviewRange.style.width = (right - left) + "px";
35753 } else {
35754 this.timeGeometry._hideLabels = true;
35755 this.plotLabels.style.visibility = "visible";
35756 this.overview.style.visibility = "hidden";
35757 this.shiftLeft.style.visibility = "hidden";
35758 this.shiftRight.style.visibility = "hidden";
35759 }
35760 },
35761
35762 /**
35763 * returns the time slices which are created by the extended data source
35764 */
35765 getSlices : function() {
35766 return this.tds.timeSlices;
35767 },
35768
35769 timeSelection : function() {
35770 var slices = this.tds.timeSlices;
35771 var ls, rs;
35772 for (var i = 0; i < slices.length; i++) {
35773 if (slices[i].date.getTime() == this.leftFlagTime.getTime())
35774 ls = i;
35775 if (slices[i].date.getTime() == this.rightFlagTime.getTime()) {
35776 if (this.style == 'graph') {
35777 rs = i;
35778 }
35779 if (this.style == 'bars') {
35780 rs = i - 1;
35781 }
35782 }
35783 }
35784 var selectedObjects = [];
35785 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
35786 selectedObjects.push([]);
35787 }
35788 for (var i = 0; i < slices.length; i++) {
35789 if (i >= ls && i <= rs) {
35790 for (var j in slices[i].stacks ) {
35791 selectedObjects[j] = selectedObjects[j].concat(slices[i].stacks[j].elements);
35792 }
35793 }
35794 }
35795 this.selection = new Selection(selectedObjects, this);
35796 this.core.triggerSelection(this.selection);
35797 this.filterBar.reset(true);
35798 },
35799
35800 deselection : function() {
35801 this.reset();
35802 this.selection = new Selection();
35803 this.core.triggerSelection(this.selection);
35804 },
35805
35806 filtering : function() {
35807 for (var i = 0; i < this.datasets.length; i++) {
35808 this.datasets[i].objects = this.selection.objects[i];
35809 }
35810 this.core.triggerRefining(this.datasets);
35811 },
35812
35813 inverseFiltering : function() {
35814 var slices = this.tds.timeSlices;
35815 var ls, rs;
35816 for (var i = 0; i < slices.length; i++) {
35817 if (slices[i].date.getTime() == this.leftFlagTime.getTime())
35818 ls = i;
35819 if (slices[i].date.getTime() == this.rightFlagTime.getTime()) {
35820 if (this.style == 'graph') {
35821 rs = i;
35822 }
35823 if (this.style == 'bars') {
35824 rs = i - 1;
35825 }
35826 }
35827 }
35828 var selectedObjects = [];
35829 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
35830 selectedObjects.push([]);
35831 }
35832 for (var i = 0; i < slices.length; i++) {
35833 if (i >= ls && i <= rs) {
35834 continue;
35835 }
35836 for (var j in slices[i].stacks ) {
35837 selectedObjects[j] = selectedObjects[j].concat(slices[i].stacks[j].elements);
35838 }
35839 }
35840 this.selection = new Selection(selectedObjects, this);
35841 this.filtering();
35842 },
35843
35844 timeHighlight : function(undo) {
35845 if (this.status == 0) {
35846 var s = this.highlightedSlice;
35847 var timeObjects = [];
35848 for (var i = 0; i < this.tds.size(); i++) {
35849 timeObjects.push([]);
35850 }
35851 var add = true;
35852 if (this.leftFlagTime != null) {
35853 if (this.style == 'graph' && s.date >= this.leftFlagTime && s.date <= this.rightFlagTime) {
35854 add = false;
35855 }
35856 if (this.style == 'bars' && s.date >= this.leftFlagTime && s.date < this.rightFlagTime) {
35857 add = false;
35858 }
35859 }
35860 if (!undo && add) {
35861 for (var i in s.stacks ) {
35862 timeObjects[i] = timeObjects[i].concat(s.stacks[i].elements);
35863 }
35864 }
35865 this.core.triggerHighlight(timeObjects);
35866 }
35867 },
35868
35869 timeRefining : function() {
35870 this.core.triggerRefining(this.selection.objects);
35871 },
35872
35873 setStyle : function(style) {
35874 this.style = style;
35875 },
35876
35877 drawLinearPlot : function() {
35878 if ( typeof this.valueGeometry != 'undefined') {
35879 this.valueGeometry.actLinear();
35880 this.timeplot.repaint();
35881 this.resetOpacityPlots();
35882 this.displayOverlay();
35883 }
35884 },
35885
35886 drawLogarithmicPlot : function() {
35887 if ( typeof this.valueGeometry != 'undefined') {
35888 this.valueGeometry.actLogarithmic();
35889 this.timeplot.repaint();
35890 this.resetOpacityPlots();
35891 this.displayOverlay();
35892 }
35893 }
35894 }
35895 /*
35896 * TableConfig.js
35897 *
35898 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
35899 *
35900 * This library is free software; you can redistribute it and/or
35901 * modify it under the terms of the GNU Lesser General Public
35902 * License as published by the Free Software Foundation; either
35903 * version 3 of the License, or (at your option) any later version.
35904 *
35905 * This library is distributed in the hope that it will be useful,
35906 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35907 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35908 * Lesser General Public License for more details.
35909 *
35910 * You should have received a copy of the GNU Lesser General Public
35911 * License along with this library; if not, write to the Free Software
35912 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35913 * MA 02110-1301 USA
35914 */
35915
35916 /**
35917 * @class TableConfig
35918 * Table Configuration File
35919 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
35920 * @release 1.0
35921 * @release date: 2012-07-27
35922 * @version date: 2012-07-27
35923 */
35924 function TableConfig(options) {
35925
35926 this.options = {
35927 tableWidth : false, // false or desired width css definition for the table
35928 tableHeight : false, // false or desired height css definition for the table
35929 validResultsPerPage : [10, 20, 50, 100], // valid number of elements per page
35930 initialResultsPerPage : 10, // initial number of elements per page
35931 tableSorting : true, // true, if sorting of columns should be possible
35932 tableContentOffset : 250, // maximum display number of characters in a table cell
35933 tableSelectPage : true, // selection of complete table pages
35934 tableSelectAll : false, // selection of complete tables
35935 tableShowSelected : true, // show selected objects only option
35936 tableKeepShowSelected : true, // don't revert to show all on "reset" (e.g. selection)
35937 tableInvertSelection : true, // show invert selection option
35938 tableSelectByText : true, // select objects by full-text search
35939 tableCreateNewFromSelected : true, // create new dataset from selected objects
35940 unselectedCellColor : '#EEE', // color for an unselected row/tab
35941 verticalAlign : 'top', // vertical alignment of the table cells ('top','center','bottom')
35942 };
35943 if ( typeof options != 'undefined') {
35944 $.extend(this.options, options);
35945 }
35946
35947 };
35948 /*
35949 * TableGui.js
35950 *
35951 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
35952 *
35953 * This library is free software; you can redistribute it and/or
35954 * modify it under the terms of the GNU Lesser General Public
35955 * License as published by the Free Software Foundation; either
35956 * version 3 of the License, or (at your option) any later version.
35957 *
35958 * This library is distributed in the hope that it will be useful,
35959 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35960 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35961 * Lesser General Public License for more details.
35962 *
35963 * You should have received a copy of the GNU Lesser General Public
35964 * License along with this library; if not, write to the Free Software
35965 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35966 * MA 02110-1301 USA
35967 */
35968
35969 /**
35970 * @class TableGui
35971 * Table GUI Implementation
35972 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
35973 * @release 1.0
35974 * @release date: 2012-07-27
35975 * @version date: 2012-07-27
35976 *
35977 * @param {TableWidget} parent table widget object
35978 * @param {HTML object} div parent div to append the table gui
35979 * @param {JSON} options table configuration
35980 */
35981 function TableGui(table, div, options) {
35982
35983 this.tableContainer = div;
35984 if (options.tableWidth) {
35985 this.tableContainer.style.width = options.tableWidth;
35986 }
35987 if (options.tableHeight) {
35988 this.tableContainer.style.height = options.tableHeight;
35989 }
35990 this.tableContainer.style.position = 'relative';
35991
35992 this.tabs = document.createElement('div');
35993 this.tabs.setAttribute('class', 'tableTabs');
35994 div.appendChild(this.tabs);
35995
35996 this.input = document.createElement('div');
35997 this.input.setAttribute('class', 'tableInput');
35998 div.appendChild(this.input);
35999
36000 };
36001 /*
36002 * TableWidget.js
36003 *
36004 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
36005 *
36006 * This library is free software; you can redistribute it and/or
36007 * modify it under the terms of the GNU Lesser General Public
36008 * License as published by the Free Software Foundation; either
36009 * version 3 of the License, or (at your option) any later version.
36010 *
36011 * This library is distributed in the hope that it will be useful,
36012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36014 * Lesser General Public License for more details.
36015 *
36016 * You should have received a copy of the GNU Lesser General Public
36017 * License along with this library; if not, write to the Free Software
36018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
36019 * MA 02110-1301 USA
36020 */
36021
36022 /**
36023 * @class TableWidget
36024 * TableWidget Implementation
36025 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
36026 * @release 1.0
36027 * @release date: 2012-07-27
36028 * @version date: 2012-07-27
36029 *
36030 * @param {TableWrapper} core wrapper for interaction to other widgets
36031 * @param {HTML object} div parent div to append the table widget div
36032 * @param {JSON} options user specified configuration that overwrites options in TableConfig.js
36033 */
36034 TableWidget = function(core, div, options) {
36035
36036 this.core = core;
36037 this.core.setWidget(this);
36038 this.tables = [];
36039 this.tableTabs = [];
36040 this.tableElements = [];
36041 this.tableHash = [];
36042
36043 this.options = (new TableConfig(options)).options;
36044 this.gui = new TableGui(this, div, this.options);
36045 this.filterBar = new FilterBar(this);
36046
36047 }
36048
36049 TableWidget.prototype = {
36050
36051 initWidget : function(data) {
36052 this.datasets = data;
36053
36054 $(this.gui.tabs).empty();
36055 $(this.gui.input).empty();
36056 this.activeTable = undefined;
36057 this.tables = [];
36058 this.tableTabs = [];
36059 this.tableElements = [];
36060 this.tableHash = [];
36061 this.selection = new Selection();
36062 this.filterBar.reset(false);
36063
36064 var tableWidget = this;
36065 var addTab = function(name, index) {
36066 var dataSet = GeoTemConfig.datasets[index];
36067 var tableTab = document.createElement('div');
36068 var tableTabTable = document.createElement('table');
36069 $(tableTab).append(tableTabTable);
36070 var tableTabTableRow = document.createElement('tr');
36071 $(tableTabTable).append(tableTabTableRow);
36072 tableTab.setAttribute('class', 'tableTab');
36073 var c = GeoTemConfig.getColor(index);
36074 tableTab.style.backgroundColor = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
36075 tableTab.onclick = function() {
36076 tableWidget.selectTable(index);
36077 }
36078 var tableNameDiv = document.createElement('div');
36079 $(tableNameDiv).append(name);
36080
36081 if (typeof dataSet.url !== "undefined"){
36082 var tableLinkDiv = document.createElement('a');
36083 tableLinkDiv.title = dataSet.url;
36084 tableLinkDiv.href = dataSet.url;
36085 tableLinkDiv.target = '_';
36086 tableLinkDiv.setAttribute('class', 'externalLink');
36087 $(tableNameDiv).append(tableLinkDiv);
36088 }
36089 $(tableTabTableRow).append($(document.createElement('td')).append(tableNameDiv));
36090
36091 var removeTabDiv = document.createElement('div');
36092 removeTabDiv.setAttribute('class', 'smallButton removeDataset');
36093 removeTabDiv.title = GeoTemConfig.getString('removeDatasetHelp');
36094 removeTabDiv.onclick = $.proxy(function(e) {
36095 GeoTemConfig.removeDataset(index);
36096 //don't let the event propagate to the DIV above
36097 e.stopPropagation();
36098 //discard link click
36099 return(false);
36100 },{index:index});
36101 $(tableTabTableRow).append($(document.createElement('td')).append(removeTabDiv));
36102
36103 if (GeoTemConfig.tableExportDataset){
36104 var exportTabDiv = document.createElement('div');
36105 exportTabDiv.setAttribute('class', 'smallButton exportDataset');
36106 exportTabDiv.title = GeoTemConfig.getString('exportDatasetHelp');
36107 var exportTabForm = document.createElement('form');
36108 //TODO: make this configurable
36109 exportTabForm.action = 'php/download.php';
36110 exportTabForm.method = 'post';
36111 var exportTabHiddenValue = document.createElement('input');
36112 exportTabHiddenValue.name = 'file';
36113 exportTabHiddenValue.type = 'hidden';
36114 exportTabForm.appendChild(exportTabHiddenValue);
36115 exportTabDiv.onclick = $.proxy(function(e) {
36116 $(exportTabHiddenValue).val(GeoTemConfig.createKMLfromDataset(index));
36117 $(exportTabForm).submit();
36118 //don't let the event propagate to the DIV
36119 e.stopPropagation();
36120 //discard link click
36121 return(false);
36122 },{index:index});
36123 exportTabDiv.appendChild(exportTabForm);
36124 $(tableTabTableRow).append($(document.createElement('td')).append(exportTabDiv));
36125 }
36126
36127 return tableTab;
36128 }
36129 tableWidget.addTab = addTab;
36130
36131 for (var i in data ) {
36132 this.tableHash.push([]);
36133 var tableTab = addTab(data[i].label, i);
36134 this.gui.tabs.appendChild(tableTab);
36135 this.tableTabs.push(tableTab);
36136 var elements = [];
36137 for (var j in data[i].objects ) {
36138 elements.push(new TableElement(data[i].objects[j]));
36139 this.tableHash[i][data[i].objects[j].index] = elements[elements.length - 1];
36140 }
36141 var table = new Table(elements, this, i);
36142 this.tables.push(table);
36143 this.tableElements.push(elements);
36144 }
36145
36146 if (data.length > 0) {
36147 this.selectTable(0);
36148 }
36149
36150 },
36151
36152 getHeight : function() {
36153 if (this.options.tableHeight) {
36154 return this.gui.tableContainer.offsetHeight - this.gui.tabs.offsetHeight;
36155 }
36156 return false;
36157 },
36158
36159 selectTable : function(index) {
36160 if (this.activeTable != index) {
36161 if ( typeof this.activeTable != 'undefined') {
36162 this.tables[this.activeTable].hide();
36163 var c = GeoTemConfig.getColor(this.activeTable);
36164 this.tableTabs[this.activeTable].style.backgroundColor = 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')';
36165 }
36166 this.activeTable = index;
36167 this.tables[this.activeTable].show();
36168 var c = GeoTemConfig.getColor(this.activeTable);
36169 this.tableTabs[this.activeTable].style.backgroundColor = 'rgb(' + c.r1 + ',' + c.g1 + ',' + c.b1 + ')';
36170 this.core.triggerRise(index);
36171 }
36172
36173 },
36174
36175 highlightChanged : function(objects) {
36176 if( !GeoTemConfig.highlightEvents || (typeof this.tables[this.activeTable] === "undefined")){
36177 return;
36178 }
36179 if( this.tables.length > 0 ){
36180 return;
36181 }
36182 for (var i = 0; i < this.tableElements.length; i++) {
36183 for (var j = 0; j < this.tableElements[i].length; j++) {
36184 this.tableElements[i][j].highlighted = false;
36185 }
36186 }
36187 for (var i = 0; i < objects.length; i++) {
36188 for (var j = 0; j < objects[i].length; j++) {
36189 this.tableHash[i][objects[i][j].index].highlighted = true;
36190 }
36191 }
36192 this.tables[this.activeTable].update();
36193 },
36194
36195 selectionChanged : function(selection) {
36196 if( !GeoTemConfig.selectionEvents || (typeof this.tables[this.activeTable] === "undefined")){
36197 return;
36198 }
36199 this.reset();
36200 if( this.tables.length == 0 ){
36201 return;
36202 }
36203 this.selection = selection;
36204 for (var i = 0; i < this.tableElements.length; i++) {
36205 for (var j = 0; j < this.tableElements[i].length; j++) {
36206 this.tableElements[i][j].selected = false;
36207 this.tableElements[i][j].highlighted = false;
36208 }
36209 }
36210 var objects = selection.getObjects(this);
36211 for (var i = 0; i < objects.length; i++) {
36212 for (var j = 0; j < objects[i].length; j++) {
36213 this.tableHash[i][objects[i][j].index].selected = true;
36214 }
36215 }
36216 this.tables[this.activeTable].reset();
36217 this.tables[this.activeTable].update();
36218 },
36219
36220 triggerHighlight : function(item) {
36221 var selectedObjects = [];
36222 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
36223 selectedObjects.push([]);
36224 }
36225 if ( typeof item != 'undefined') {
36226 selectedObjects[this.activeTable].push(item);
36227 }
36228 this.core.triggerHighlight(selectedObjects);
36229 },
36230
36231 tableSelection : function() {
36232 var selectedObjects = [];
36233 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
36234 selectedObjects.push([]);
36235 }
36236 var valid = false;
36237 for (var i = 0; i < this.tableElements.length; i++) {
36238 for (var j = 0; j < this.tableElements[i].length; j++) {
36239 var e = this.tableElements[i][j];
36240 if (e.selected) {
36241 selectedObjects[i].push(e.object);
36242 valid = true;
36243 }
36244 }
36245 }
36246 this.selection = new Selection();
36247 if (valid) {
36248 this.selection = new Selection(selectedObjects, this);
36249 }
36250 this.core.triggerSelection(this.selection);
36251 this.filterBar.reset(true);
36252 },
36253
36254 deselection : function() {
36255 this.reset();
36256 this.selection = new Selection();
36257 this.core.triggerSelection(this.selection);
36258 },
36259
36260 filtering : function() {
36261 for (var i = 0; i < this.datasets.length; i++) {
36262 this.datasets[i].objects = this.selection.objects[i];
36263 }
36264 this.core.triggerRefining(this.datasets);
36265 },
36266
36267 inverseFiltering : function() {
36268 var selectedObjects = [];
36269 for (var i = 0; i < GeoTemConfig.datasets.length; i++) {
36270 selectedObjects.push([]);
36271 }
36272 var valid = false;
36273 for (var i = 0; i < this.tableElements.length; i++) {
36274 for (var j = 0; j < this.tableElements[i].length; j++) {
36275 var e = this.tableElements[i][j];
36276 if (!e.selected) {
36277 selectedObjects[i].push(e.object);
36278 valid = true;
36279 }
36280 }
36281 }
36282 this.selection = new Selection();
36283 if (valid) {
36284 this.selection = new Selection(selectedObjects, this);
36285 }
36286 this.filtering();
36287 },
36288
36289 triggerRefining : function() {
36290 this.core.triggerRefining(this.selection.objects);
36291 },
36292
36293 reset : function() {
36294 this.filterBar.reset(false);
36295 if( this.tables.length > 0 ){
36296 this.tables[this.activeTable].resetElements();
36297 this.tables[this.activeTable].reset();
36298 this.tables[this.activeTable].update();
36299 }
36300 }
36301 }
36302 /*
36303 * Table.js
36304 *
36305 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
36306 *
36307 * This library is free software; you can redistribute it and/or
36308 * modify it under the terms of the GNU Lesser General Public
36309 * License as published by the Free Software Foundation; either
36310 * version 3 of the License, or (at your option) any later version.
36311 *
36312 * This library is distributed in the hope that it will be useful,
36313 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36314 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36315 * Lesser General Public License for more details.
36316 *
36317 * You should have received a copy of the GNU Lesser General Public
36318 * License along with this library; if not, write to the Free Software
36319 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
36320 * MA 02110-1301 USA
36321 */
36322
36323 /**
36324 * @class Table
36325 * Implementation for a single table
36326 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
36327 * @release 1.0
36328 * @release date: 2012-07-27
36329 * @version date: 2012-07-27
36330 *
36331 * @param {Array} elements list of data items
36332 * @param {HTML object} parent div to append the table
36333 * @param {int} id dataset index
36334 */
36335 function Table(elements, parent, id) {
36336
36337 this.elements = elements;
36338 this.showElementsLength = elements.length;
36339 this.parent = parent;
36340 this.id = id;
36341 this.options = parent.options;
36342
36343 this.validResultsPerPage = [10, 20, 50, 100];
36344 this.keyHeaderList = [];
36345 this.initialize();
36346
36347 }
36348
36349 Table.prototype = {
36350
36351 initToolbar : function() {
36352
36353 var table = this;
36354
36355 this.toolbar = document.createElement("table");
36356 this.toolbar.setAttribute('class', 'ddbToolbar');
36357 this.toolbar.style.overflow = 'auto';
36358 this.tableDiv.appendChild(this.toolbar);
36359
36360 var navigation = document.createElement("tr");
36361 this.toolbar.appendChild(navigation);
36362
36363 var selectors = document.createElement("td");
36364 navigation.appendChild(selectors);
36365
36366 if (table.options.tableSelectPage) {
36367 var selectPageItems = true;
36368 this.selectPage = document.createElement('div');
36369 $(this.selectPage).css("float","left");
36370 this.selectPage.setAttribute('class', 'smallButton selectPage');
36371 this.selectPage.title = GeoTemConfig.getString('selectTablePageItemsHelp');
36372 selectors.appendChild(this.selectPage);
36373 this.selectPage.onclick = function() {
36374 selectPageItems = !selectPageItems;
36375 if (selectPageItems) {
36376 var items = 0;
36377 for (var i = table.first; i < table.elements.length; i++) {
36378 table.elements[i].selected = false;
36379 items++;
36380 if (items == table.resultsPerPage) {
36381 break;
36382 }
36383 }
36384 table.selectPage.setAttribute('class', 'smallButton selectPage');
36385 table.selectPage.title = GeoTemConfig.getString('selectTablePageItemsHelp');
36386 } else {
36387 var items = 0;
36388 for (var i = table.first; i < table.elements.length; i++) {
36389 table.elements[i].selected = true;
36390 items++;
36391 if (items == table.resultsPerPage) {
36392 break;
36393 }
36394 }
36395 table.selectPage.setAttribute('class', 'smallButton deselectPage');
36396 table.selectPage.title = GeoTemConfig.getString('deselectTablePageItemsHelp');
36397 }
36398 table.update();
36399 table.parent.tableSelection();
36400 }
36401 }
36402
36403 if (table.options.tableSelectAll) {
36404 var selectAllItems = true;
36405 this.selectAll = document.createElement('div');
36406 this.selectAll.setAttribute('class', 'smallButton selectAll');
36407 $(this.selectAll).css("float","left");
36408 table.selectAll.title = GeoTemConfig.getString('selectAllTableItemsHelp');
36409 selectors.appendChild(this.selectAll);
36410 this.selectAll.onclick = function() {
36411 selectAllItems = !selectAllItems;
36412 if (selectAllItems) {
36413 for (var i = 0; i < table.elements.length; i++) {
36414 table.elements[i].selected = false;
36415 }
36416 table.selectAll.setAttribute('class', 'smallButton selectAll');
36417 table.selectAll.title = GeoTemConfig.getString('selectAllTableItemsHelp');
36418 } else {
36419 for (var i = 0; i < table.elements.length; i++) {
36420 table.elements[i].selected = true;
36421 }
36422 table.selectAll.setAttribute('class', 'smallButton deselectAll');
36423 table.selectAll.title = GeoTemConfig.getString('deselectAllTableItemsHelp');
36424 }
36425 table.update();
36426 table.parent.tableSelection();
36427 }
36428 }
36429
36430 if (table.options.tableInvertSelection) {
36431 this.invertSelection = document.createElement('div');
36432 this.invertSelection.setAttribute('class', 'smallButton invertSelection');
36433 $(this.invertSelection).css("float","left");
36434 table.invertSelection.title = GeoTemConfig.getString('invertSelectionHelp');
36435 selectors.appendChild(this.invertSelection);
36436 this.invertSelection.onclick = function() {
36437 for (var i = 0; i < table.elements.length; i++) {
36438 if (table.elements[i].selected === true)
36439 table.elements[i].selected = false;
36440 else
36441 table.elements[i].selected = true;
36442 }
36443 table.update();
36444 table.parent.tableSelection();
36445 }
36446 }
36447
36448 this.showSelectedItems = false;
36449 if (table.options.tableShowSelected) {
36450 this.showSelected = document.createElement('div');
36451 this.showSelected.setAttribute('class', 'smallButton showSelected');
36452 $(this.showSelected).css("float","left");
36453 table.showSelected.title = GeoTemConfig.getString('showSelectedHelp');
36454 selectors.appendChild(this.showSelected);
36455 this.showSelected.onclick = function() {
36456 table.showSelectedItems = !table.showSelectedItems;
36457 if (table.showSelectedItems) {
36458 table.showElementsLength = 0;
36459 for (var i = 0; i < table.elements.length; i++) {
36460 if (table.elements[i].selected) {
36461 table.showElementsLength++;
36462 }
36463 }
36464 table.showSelected.setAttribute('class', 'smallButton showAll');
36465 // table.selectAll.title = GeoTemConfig.getString('showAllElementsHelp');
36466 } else {
36467 table.showElementsLength = table.elements.length;
36468 table.showSelected.setAttribute('class', 'smallButton showSelected');
36469 // table.selectAll.title = GeoTemConfig.getString('showSelectedHelp');
36470 }
36471 table.updateIndices(table.resultsPerPage);
36472 table.update();
36473 }
36474 }
36475
36476 if (table.options.tableSelectByText) {
36477 this.selectByTextDiv = document.createElement('div');
36478 $(this.selectByTextDiv).css("float","left");
36479 $(this.selectByTextDiv).css("vertical-align", "top");
36480 //TODO: improve appearance (wrong margin)
36481 $(this.selectByTextDiv).css("display", "inline-block");
36482 //create and append the input field
36483 this.selectByTextInput = document.createElement('input');
36484 $(this.selectByTextInput).attr("type","text");
36485 $(this.selectByTextDiv).append(this.selectByTextInput);
36486 //create and append the button
36487 this.selectByTextButton = document.createElement('input');
36488 $(this.selectByTextButton).attr("type","button");
36489 //TODO: add button-image
36490 $(this.selectByTextButton).val("search");
36491 $(this.selectByTextDiv).append(this.selectByTextButton);
36492
36493 table.selectByTextDiv.title = GeoTemConfig.getString('selectByTextHelp');
36494 selectors.appendChild(this.selectByTextDiv);
36495 $(this.selectByTextButton).click($.proxy(function() {
36496 this.selectByText($(this.selectByTextInput).val());
36497 },this));
36498 }
36499
36500 if (table.options.tableCreateNewFromSelected) {
36501 this.createNewFromSelected = document.createElement('div');
36502 this.createNewFromSelected.setAttribute('class', 'smallButton createNewRefined');
36503 $(this.createNewFromSelected).css("float","left");
36504 this.createNewFromSelected.title = GeoTemConfig.getString('createNewFromSelectedHelp');
36505 selectors.appendChild(this.createNewFromSelected);
36506 this.createNewFromSelected.onclick = function() {
36507 var copyID = table.id;
36508 var tableWidget = table.parent;
36509
36510 var newObjects = [];
36511 $(table.elements).each(function(){
36512 if (this.selected)
36513 newObjects.push(this.object);
36514 });
36515
36516 var newDataset = new Dataset();
36517 newDataset.label = tableWidget.datasets[copyID].label + " refined";
36518 newDataset.objects = newObjects;
36519
36520 GeoTemConfig.addDataset(newDataset);
36521 };
36522 }
36523
36524 this.selectors = selectors;
36525
36526 // selectors.style.width = (this.filter.offsetWidth + this.selectAll.offsetWidth + this.selectPage.offsetWidth)+"px";
36527
36528 var results = document.createElement("td");
36529 navigation.appendChild(results);
36530
36531 var pagination = document.createElement("td");
36532 $(pagination).css('float', 'right');
36533 navigation.appendChild(pagination);
36534
36535 this.resultsInfo = document.createElement('div');
36536 this.resultsInfo.setAttribute('class', 'resultsInfo');
36537 results.appendChild(this.resultsInfo);
36538
36539 this.resultsDropdown = document.createElement('div');
36540 this.resultsDropdown.setAttribute('class', 'resultsDropdown');
36541 pagination.appendChild(this.resultsDropdown);
36542 var itemNumbers = [];
36543 var addItemNumber = function(count, index) {
36544 var setItemNumber = function() {
36545 table.updateIndices(count);
36546 table.update();
36547 }
36548 itemNumbers.push({
36549 name : count,
36550 onclick : setItemNumber
36551 });
36552 }
36553 for (var i = 0; i < table.options.validResultsPerPage.length; i++) {
36554 addItemNumber(table.options.validResultsPerPage[i], i);
36555 }
36556 var dropdown = new Dropdown(this.resultsDropdown, itemNumbers, GeoTemConfig.getString('paginationDropdownHelp'));
36557 for (var i = 0; i < table.options.validResultsPerPage.length; i++) {
36558 if (table.options.initialResultsPerPage == table.options.validResultsPerPage[i]) {
36559 dropdown.setEntry(i);
36560 break;
36561 }
36562 }
36563 dropdown.div.title = GeoTemConfig.getString('paginationDropdownHelp');
36564
36565 this.firstPage = document.createElement('div');
36566 this.firstPage.setAttribute('class', 'paginationButton');
36567 this.firstPage.title = GeoTemConfig.getString('paginationFirsPageHelp');
36568
36569 pagination.appendChild(this.firstPage);
36570 this.firstPage.onclick = function() {
36571 if (table.page != 0) {
36572 table.page = 0;
36573 table.update();
36574 }
36575 }
36576
36577 this.previousPage = document.createElement('div');
36578 this.previousPage.setAttribute('class', 'paginationButton');
36579 this.previousPage.title = GeoTemConfig.getString('paginationPreviousPageHelp');
36580 pagination.appendChild(this.previousPage);
36581 this.previousPage.onclick = function() {
36582 if (table.page > 0) {
36583 table.page--;
36584 table.update();
36585 }
36586 }
36587
36588 this.pageInfo = document.createElement('div');
36589 this.pageInfo.setAttribute('class', 'pageInfo');
36590 pagination.appendChild(this.pageInfo);
36591
36592 this.nextPage = document.createElement('div');
36593 this.nextPage.setAttribute('class', 'paginationButton');
36594 this.nextPage.title = GeoTemConfig.getString('paginationNextPageHelp');
36595 pagination.appendChild(this.nextPage);
36596 this.nextPage.onclick = function() {
36597 if (table.page < table.pages - 1) {
36598 table.page++;
36599 table.update();
36600 }
36601 }
36602
36603 this.lastPage = document.createElement('div');
36604 this.lastPage.setAttribute('class', 'paginationButton');
36605 this.lastPage.title = GeoTemConfig.getString('paginationLastPageHelp');
36606 pagination.appendChild(this.lastPage);
36607 this.lastPage.onclick = function() {
36608 if (table.page != table.pages - 1) {
36609 table.page = table.pages - 1;
36610 table.update();
36611 }
36612 }
36613
36614 this.input = document.createElement("div");
36615 this.input.style.overflow = 'auto';
36616 this.tableDiv.appendChild(this.input);
36617
36618 this.elementList = document.createElement("table");
36619 this.elementList.setAttribute('class', 'resultList');
36620 this.input.appendChild(this.elementList);
36621 var height = this.parent.getHeight();
36622 if (height) {
36623 this.input.style.height = (height - pagination.offsetHeight) + 'px';
36624 this.input.style.overflowY = 'auto';
36625 }
36626
36627 this.elementListHeader = document.createElement("tr");
36628 this.elementList.appendChild(this.elementListHeader);
36629
36630 if (GeoTemConfig.allowFilter) {
36631 var cell = document.createElement('th');
36632 this.elementListHeader.appendChild(cell);
36633 }
36634
36635 //Bottom pagination elements
36636 this.bottomToolbar = document.createElement("table");
36637 this.bottomToolbar.setAttribute('class', 'ddbToolbar');
36638 this.bottomToolbar.style.overflow = 'auto';
36639 this.tableDiv.appendChild(this.bottomToolbar);
36640
36641 var bottomNavigation = document.createElement("tr");
36642 this.bottomToolbar.appendChild(bottomNavigation);
36643
36644 var bottomPagination = document.createElement("td");
36645 bottomNavigation.appendChild(bottomPagination);
36646
36647 this.bottomLastPage = document.createElement('div');
36648 this.bottomLastPage.setAttribute('class', 'paginationButton');
36649 this.bottomLastPage.title = GeoTemConfig.getString('paginationLastPageHelp');
36650 $(this.bottomLastPage).css('float', 'right');
36651 bottomPagination.appendChild(this.bottomLastPage);
36652 this.bottomLastPage.onclick = function() {
36653 if (table.page != table.pages - 1) {
36654 table.page = table.pages - 1;
36655 table.update();
36656 }
36657 }
36658
36659 this.bottomNextPage = document.createElement('div');
36660 this.bottomNextPage.setAttribute('class', 'paginationButton');
36661 this.bottomNextPage.title = GeoTemConfig.getString('paginationNextPageHelp');
36662 $(this.bottomNextPage).css('float', 'right');
36663 bottomPagination.appendChild(this.bottomNextPage);
36664 this.bottomNextPage.onclick = function() {
36665 if (table.page < table.pages - 1) {
36666 table.page++;
36667 table.update();
36668 }
36669 }
36670
36671 this.bottomPageInfo = document.createElement('div');
36672 this.bottomPageInfo.setAttribute('class', 'pageInfo');
36673 $(this.bottomPageInfo).css('float', 'right');
36674 bottomPagination.appendChild(this.bottomPageInfo);
36675
36676 this.bottomPreviousPage = document.createElement('div');
36677 this.bottomPreviousPage.setAttribute('class', 'paginationButton');
36678 this.bottomPreviousPage.title = GeoTemConfig.getString('paginationPreviousPageHelp');
36679 $(this.bottomPreviousPage).css('float', 'right');
36680 bottomPagination.appendChild(this.bottomPreviousPage);
36681 this.bottomPreviousPage.onclick = function() {
36682 if (table.page > 0) {
36683 table.page--;
36684 table.update();
36685 }
36686 }
36687
36688 this.bottomFirstPage = document.createElement('div');
36689 this.bottomFirstPage.setAttribute('class', 'paginationButton');
36690 this.bottomFirstPage.title = GeoTemConfig.getString('paginationFirsPageHelp');
36691 $(this.bottomFirstPage).css('float', 'right');
36692 bottomPagination.appendChild(this.bottomFirstPage);
36693 this.bottomFirstPage.onclick = function() {
36694 if (table.page != 0) {
36695 table.page = 0;
36696 table.update();
36697 }
36698 }
36699
36700 if ( typeof (this.elements[0]) == 'undefined') {
36701 return;
36702 }
36703
36704 var ascButtons = [];
36705 var descButtons = [];
36706 var clearButtons = function() {
36707 for (var i in ascButtons ) {
36708 ascButtons[i].setAttribute('class', 'sort sortAscDeactive');
36709 }
36710 for (var i in descButtons ) {
36711 descButtons[i].setAttribute('class', 'sort sortDescDeactive');
36712 }
36713 }
36714 var addSortButton = function(key) {
36715 table.keyHeaderList.push(key);
36716 var cell = document.createElement('th');
36717 table.elementListHeader.appendChild(cell);
36718 var sortAsc = document.createElement('div');
36719 var sortDesc = document.createElement('div');
36720 var span = document.createElement('div');
36721 span.setAttribute('class', 'headerLabel');
36722 span.innerHTML = key;
36723 cell.appendChild(sortDesc);
36724 cell.appendChild(span);
36725 cell.appendChild(sortAsc);
36726 sortAsc.setAttribute('class', 'sort sortAscDeactive');
36727 sortAsc.title = GeoTemConfig.getString('sortAZHelp');
36728 sortDesc.setAttribute('class', 'sort sortDescDeactive');
36729 sortDesc.title = GeoTemConfig.getString('sortZAHelp');
36730 ascButtons.push(sortAsc);
36731 descButtons.push(sortDesc);
36732 sortAsc.onclick = function() {
36733 clearButtons();
36734 sortAsc.setAttribute('class', 'sort sortAscActive');
36735 table.sortAscending(key);
36736 table.update();
36737 }
36738 sortDesc.onclick = function() {
36739 clearButtons();
36740 sortDesc.setAttribute('class', 'sort sortDescActive');
36741 table.sortDescending(key);
36742 table.update();
36743 }
36744 }
36745 for (var key in this.elements[0].object.tableContent) {
36746 addSortButton(key);
36747 }
36748 },
36749
36750 sortAscending : function(key) {
36751 var sortFunction = function(e1, e2) {
36752 if (e1.object.tableContent[key] < e2.object.tableContent[key]) {
36753 return -1;
36754 }
36755 return 1;
36756 }
36757 this.elements.sort(sortFunction);
36758 },
36759
36760 sortDescending : function(key) {
36761 var sortFunction = function(e1, e2) {
36762 if (e1.object.tableContent[key] > e2.object.tableContent[key]) {
36763 return -1;
36764 }
36765 return 1;
36766 }
36767 this.elements.sort(sortFunction);
36768 },
36769
36770 selectByText : function(text) {
36771 //deselect all elements
36772 $(this.elements).each(function(){
36773 this.selected = false;
36774 });
36775
36776 var selectedCount = 0;
36777 $(this.elements).filter(function(index){
36778 return this.object.contains(text);
36779 }).each(function(){
36780 this.selected = true;
36781 selectedCount++;
36782 });
36783
36784 //only show selected elements
36785 this.showSelectedItems = true;
36786 this.showElementsLength = selectedCount;
36787 this.showSelected.setAttribute('class', 'smallButton showAll');
36788
36789 this.update();
36790 this.parent.tableSelection();
36791 },
36792
36793 setPagesText : function() {
36794 var infoText = GeoTemConfig.getString('pageInfo');
36795 infoText = infoText.replace('PAGES_ID', this.pages);
36796 infoText = infoText.replace('PAGE_ID', this.page + 1);
36797 this.pageInfo.innerHTML = infoText;
36798 this.bottomPageInfo.innerHTML = infoText;
36799 },
36800
36801 setResultsText : function() {
36802 if (this.elements.length == 0) {
36803 this.resultsInfo.innerHTML = '0 Results';
36804 } else {
36805 var infoText = GeoTemConfig.getString('resultsInfo');
36806 var first = this.page * this.resultsPerPage + 1;
36807 var last = (this.page + 1 == this.pages ) ? this.showElementsLength : first + this.resultsPerPage - 1;
36808 infoText = infoText.replace('RESULTS_FROM_ID', first);
36809 infoText = infoText.replace('RESULTS_TO_ID', last);
36810 infoText = infoText.replace('RESULTS_ID', this.showElementsLength);
36811 this.resultsInfo.innerHTML = infoText;
36812 }
36813 },
36814
36815 updateIndices : function(rpp) {
36816 if ( typeof this.resultsPerPage == 'undefined') {
36817 this.page = 0;
36818 this.resultsPerPage = 0;
36819 }
36820 var index = this.page * this.resultsPerPage;
36821 this.resultsPerPage = rpp;
36822 if (this.showSelectedItems) {
36823 index = 0;
36824 }
36825 this.pages = Math.floor(this.showElementsLength / this.resultsPerPage);
36826 if (this.showElementsLength % this.resultsPerPage != 0) {
36827 this.pages++;
36828 }
36829 this.page = Math.floor(index / this.resultsPerPage);
36830 },
36831
36832 update : function() {
36833 var table = this;
36834 $(this.elementList).find("tr:gt(0)").remove();
36835 if (this.page == 0) {
36836 this.previousPage.setAttribute('class', 'paginationButton previousPageDisabled');
36837 this.firstPage.setAttribute('class', 'paginationButton firstPageDisabled');
36838 this.bottomPreviousPage.setAttribute('class', 'paginationButton previousPageDisabled');
36839 this.bottomFirstPage.setAttribute('class', 'paginationButton firstPageDisabled');
36840 } else {
36841 this.previousPage.setAttribute('class', 'paginationButton previousPageEnabled');
36842 this.firstPage.setAttribute('class', 'paginationButton firstPageEnabled');
36843 this.bottomPreviousPage.setAttribute('class', 'paginationButton previousPageEnabled');
36844 this.bottomFirstPage.setAttribute('class', 'paginationButton firstPageEnabled');
36845 }
36846 if (this.page == this.pages - 1) {
36847 this.nextPage.setAttribute('class', 'paginationButton nextPageDisabled');
36848 this.lastPage.setAttribute('class', 'paginationButton lastPageDisabled');
36849 this.bottomNextPage.setAttribute('class', 'paginationButton nextPageDisabled');
36850 this.bottomLastPage.setAttribute('class', 'paginationButton lastPageDisabled');
36851 } else {
36852 this.nextPage.setAttribute('class', 'paginationButton nextPageEnabled');
36853 this.lastPage.setAttribute('class', 'paginationButton lastPageEnabled');
36854 this.bottomNextPage.setAttribute('class', 'paginationButton nextPageEnabled');
36855 this.bottomLastPage.setAttribute('class', 'paginationButton lastPageEnabled');
36856 }
36857 this.setPagesText();
36858 this.setResultsText();
36859 if (this.showSelectedItems) {
36860 var start = this.page * this.resultsPerPage;
36861 var items = 0;
36862 for (var i = 0; i < this.elements.length; i++) {
36863 if (items == start) {
36864 this.first = i;
36865 break;
36866 }
36867 if (this.elements[i].selected) {
36868 items++;
36869 }
36870 }
36871 } else {
36872 this.first = this.page * this.resultsPerPage;
36873 }
36874 //this.last = ( this.page + 1 == this.pages ) ? this.elements.length : this.first + this.resultsPerPage;
36875 var c = GeoTemConfig.getColor(this.id);
36876 var itemSet = [];
36877 var clearDivs = function() {
36878 for (var i = 0; i < itemSet.length; i++) {
36879 if (!itemSet[i].e.selected) {
36880 itemSet[i].e.highlighted = false;
36881 $(itemSet[i].div).css('background-color', table.options.unselectedCellColor);
36882 }
36883 }
36884 }
36885 var setHighlight = function(item, div) {
36886 var enter = function() {
36887 clearDivs();
36888 if (!item.selected) {
36889 item.highlighted = true;
36890 $(div).css('background-color', 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')');
36891 table.parent.triggerHighlight(item.object);
36892 }
36893 }
36894 var leave = function() {
36895 clearDivs();
36896 if (!item.selected) {
36897 table.parent.triggerHighlight();
36898 }
36899 }
36900 $(div).hover(enter, leave);
36901 $(div).mousemove(function() {
36902 if (!item.selected && !item.highlighted) {
36903 item.highlighted = true;
36904 $(div).css('background-color', 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')');
36905 table.parent.triggerHighlight(item.object);
36906 }
36907 });
36908 }
36909 var setSelection = function(item, div, checkbox) {
36910 var click = function(e) {
36911 var checked = $(checkbox).is(':checked');
36912 if (checked) {
36913 item.selected = true;
36914 item.highlighted = false;
36915 } else {
36916 item.selected = false;
36917 item.highlighted = true;
36918 }
36919 //if( e.target == div ){
36920 // $(checkbox).attr('checked', !checked);
36921 //}
36922 table.parent.tableSelection();
36923 }
36924 //$(div).click(click);
36925 $(checkbox).click(click);
36926 }
36927 this.checkboxes = [];
36928 var items = 0;
36929 for (var i = this.first; i < this.elements.length; i++) {
36930 var e = this.elements[i];
36931 //vhz because of an error
36932 if ( typeof (e) == "undefined") {
36933 continue;
36934 }
36935 if (this.showSelectedItems && !e.selected) {
36936 continue;
36937 }
36938 var itemRow = $("<tr/>").appendTo(this.elementList);
36939 if (GeoTemConfig.allowFilter) {
36940 var checkColumn = $("<td/>").appendTo(itemRow);
36941 var checkbox = $("<input type='checkbox'/>").appendTo(checkColumn);
36942 $(checkbox).attr('checked', e.selected);
36943 }
36944 var makeSubtext = function(cell, text) {
36945 var subtext = text.substring(0, table.options.tableContentOffset);
36946 subtext = subtext.substring(0, subtext.lastIndexOf(' '));
36947 subtext += ' ... ';
36948 var textDiv = $("<div style='display:inline-block;'/>").appendTo(cell);
36949 $(textDiv).html(subtext);
36950 var show = false;
36951 var fullDiv = $("<div style='display:inline-block;'><a href='javascript:void(0)'>\>\></a></div>").appendTo(cell);
36952 $(fullDiv).click(function() {
36953 show = !show;
36954 if (show) {
36955 $(textDiv).html(text);
36956 $(fullDiv).html('<a href="javascript:void(0)">\<\<</a>');
36957 } else {
36958 $(textDiv).html(subtext);
36959 $(fullDiv).html('<a href="javascript:void(0)">\>\></a>');
36960 }
36961 });
36962 }
36963 for (var k = 0; k < table.keyHeaderList.length; k++) {
36964 var key = table.keyHeaderList[k];
36965 //vhz
36966 var text = e.object.tableContent[key];
36967 if (typeof text === "undefined")
36968 text = "";
36969 var cell = $("<td></td>").appendTo(itemRow);
36970
36971 //align the elements (if unset: "center")
36972 if (typeof table.options.verticalAlign !== "undefined"){
36973 if (table.options.verticalAlign === "top")
36974 $(cell).attr("valign","top");
36975 else if (table.options.verticalAlign === "center")
36976 $(cell).attr("valign","center");
36977 else if (table.options.verticalAlign === "bottom")
36978 $(cell).attr("valign","bottom");
36979 }
36980
36981 if (table.options.tableContentOffset && text.length < table.options.tableContentOffset) {
36982 $(cell).html(text);
36983 } else {
36984 makeSubtext(cell, text);
36985 }
36986 }
36987 if (e.selected || e.highlighted) {
36988 $(itemRow).css('background-color', 'rgb(' + c.r0 + ',' + c.g0 + ',' + c.b0 + ')');
36989 } else {
36990 $(itemRow).css('background-color', table.options.unselectedCellColor);
36991 }
36992 itemSet.push({
36993 e : e,
36994 div : itemRow
36995 });
36996 setHighlight(e, itemRow);
36997 if (GeoTemConfig.allowFilter) {
36998 setSelection(e, itemRow, checkbox);
36999 this.checkboxes.push(checkbox);
37000 $(checkColumn).css('text-align', 'center');
37001 }
37002 items++;
37003 if (items == this.resultsPerPage) {
37004 break;
37005 }
37006 }
37007 },
37008
37009 show : function() {
37010 if (GeoTemConfig.allowFilter) {
37011 this.parent.filterBar.appendTo(this.selectors);
37012 }
37013 this.tableDiv.style.display = "block";
37014 },
37015
37016 hide : function() {
37017 this.tableDiv.style.display = "none";
37018 },
37019
37020 resetElements : function() {
37021 for (var i = 0; i < this.elements.length; i++) {
37022 this.elements[i].selected = false;
37023 this.elements[i].highlighted = false;
37024 }
37025 },
37026
37027 reset : function() {
37028 if (!this.options.tableKeepShowSelected){
37029 this.showSelectedItems = false;
37030 this.showElementsLength = this.elements.length;
37031 this.showSelected.setAttribute('class', 'smallButton showSelected');
37032 }
37033 this.updateIndices(this.resultsPerPage);
37034 },
37035
37036 initialize : function() {
37037
37038 this.tableDiv = document.createElement("div");
37039 this.tableDiv.setAttribute('class', 'singleTable');
37040 this.parent.gui.input.appendChild(this.tableDiv);
37041
37042 this.initToolbar();
37043
37044 this.tableDiv.style.display = 'none';
37045 this.updateIndices(this.options.initialResultsPerPage);
37046
37047 this.update();
37048
37049 }
37050 }
37051
37052 function TableElement(object) {
37053
37054 this.object = object;
37055 this.selected = false;
37056 this.highlighted = false;
37057
37058 }
37059 /*
37060 * Dataloader.js
37061 *
37062 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
37063 *
37064 * This library is free software; you can redistribute it and/or
37065 * modify it under the terms of the GNU Lesser General Public
37066 * License as published by the Free Software Foundation; either
37067 * version 3 of the License, or (at your option) any later version.
37068 *
37069 * This library is distributed in the hope that it will be useful,
37070 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37071 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37072 * Lesser General Public License for more details.
37073 *
37074 * You should have received a copy of the GNU Lesser General Public
37075 * License along with this library; if not, write to the Free Software
37076 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37077 * MA 02110-1301 USA
37078 */
37079
37080 /**
37081 * @class Dataloader
37082 * Implementation for a Dataloader UI
37083 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
37084 *
37085 * @param {HTML object} parent div to append the Dataloader
37086 */
37087 function Dataloader(parent) {
37088
37089 this.dataLoader = this;
37090
37091 this.parent = parent;
37092 this.options = parent.options;
37093
37094 this.initialize();
37095 }
37096
37097 Dataloader.prototype = {
37098
37099 show : function() {
37100 this.dataloaderDiv.style.display = "block";
37101 },
37102
37103 hide : function() {
37104 this.dataloaderDiv.style.display = "none";
37105 },
37106
37107 initialize : function() {
37108
37109 this.addStaticLoader();
37110 this.addLocalStorageLoader();
37111 this.addKMLLoader();
37112 this.addKMZLoader();
37113 this.addCSVLoader();
37114 this.addLocalKMLLoader();
37115 this.addLocalCSVLoader();
37116
37117 // trigger change event on the select so
37118 // that only the first loader div will be shown
37119 $(this.parent.gui.loaderTypeSelect).change();
37120 },
37121
37122 getFileName : function(url) {
37123 var fileName = $.url(url).attr('file');
37124 if ( (typeof fileName === "undefined") || (fileName.length === 0) ){
37125 fileName = $.url(url).attr('path');
37126 //startsWith and endsWith defined in SIMILE Ajax (string.js)
37127 while (fileName.endsWith("/")){
37128 fileName = fileName.substr(0,fileName.length-1);
37129 }
37130 if (fileName.length > 1)
37131 fileName = fileName.substr(fileName.lastIndexOf("/")+1);
37132 else
37133 fileName = "unnamed dataset";
37134 }
37135 return fileName;
37136 },
37137
37138 distributeDataset : function(dataSet) {
37139 GeoTemConfig.addDataset(dataSet);
37140 },
37141
37142 distributeDatasets : function(datasets) {
37143 GeoTemConfig.addDatasets(datasets);
37144 },
37145
37146 addStaticLoader : function() {
37147 if (this.options.staticKML.length > 0){
37148 $(this.parent.gui.loaderTypeSelect).append("<option value='StaticLoader'>Static Data</option>");
37149
37150 this.StaticLoaderTab = document.createElement("div");
37151 $(this.StaticLoaderTab).attr("id","StaticLoader");
37152
37153 this.staticKMLList = document.createElement("select");
37154 $(this.StaticLoaderTab).append(this.staticKMLList);
37155
37156 var staticKMLList = this.staticKMLList;
37157 var isFirstHeader = true;
37158 $(this.options.staticKML).each(function(){
37159 var label = this.label;
37160 var url = this.url;
37161 var header = this.header;
37162 if (typeof header !== "undefined"){
37163 if (!isFirstHeader)
37164 $(staticKMLList).append("</optgroup>");
37165 $(staticKMLList).append("<optgroup label='"+header+"'>");
37166 isFirstHeader = false;
37167 } else
37168 $(staticKMLList).append("<option value='"+url+"'> "+label+"</option>");
37169 });
37170 //close last optgroup (if there were any)
37171 if (!isFirstHeader)
37172 $(staticKMLList).append("</optgroup>");
37173
37174 this.loadStaticKMLButton = document.createElement("button");
37175 $(this.loadStaticKMLButton).text("load");
37176 $(this.StaticLoaderTab).append(this.loadStaticKMLButton);
37177
37178 $(this.loadStaticKMLButton).click($.proxy(function(){
37179 var kmlURL = $(this.staticKMLList).find(":selected").attr("value");
37180 if (kmlURL.length === 0)
37181 return;
37182 var origURL = kmlURL;
37183 var fileName = this.getFileName(kmlURL);
37184 if (typeof this.options.proxy != 'undefined')
37185 kmlURL = this.options.proxy + kmlURL;
37186 var kml = GeoTemConfig.getKml(kmlURL);
37187 if ((typeof kml !== "undefined") && (kml != null)) {
37188 var dataSet = new Dataset(GeoTemConfig.loadKml(kml), fileName, origURL);
37189
37190 if (dataSet != null)
37191 this.distributeDataset(dataSet);
37192 } else
37193 alert("Could not load file.");
37194 },this));
37195
37196 $(this.parent.gui.loaders).append(this.StaticLoaderTab);
37197 }
37198 },
37199
37200 addKMLLoader : function() {
37201 $(this.parent.gui.loaderTypeSelect).append("<option value='KMLLoader'>KML File URL</option>");
37202
37203 this.KMLLoaderTab = document.createElement("div");
37204 $(this.KMLLoaderTab).attr("id","KMLLoader");
37205
37206 this.kmlURL = document.createElement("input");
37207 $(this.kmlURL).attr("type","text");
37208 $(this.KMLLoaderTab).append(this.kmlURL);
37209
37210 this.loadKMLButton = document.createElement("button");
37211 $(this.loadKMLButton).text("load KML");
37212 $(this.KMLLoaderTab).append(this.loadKMLButton);
37213
37214 $(this.loadKMLButton).click($.proxy(function(){
37215 var kmlURL = $(this.kmlURL).val();
37216 if (kmlURL.length === 0)
37217 return;
37218 var origURL = kmlURL;
37219 var fileName = this.getFileName(kmlURL);
37220 if (typeof this.options.proxy != 'undefined')
37221 kmlURL = this.options.proxy + kmlURL;
37222 var kml = GeoTemConfig.getKml(kmlURL);
37223 if ((typeof kml !== "undefined") && (kml != null)) {
37224 var dataSet = new Dataset(GeoTemConfig.loadKml(kml), fileName, origURL);
37225
37226 if (dataSet != null)
37227 this.distributeDataset(dataSet);
37228 } else
37229 alert("Could not load file.");
37230 },this));
37231
37232 $(this.parent.gui.loaders).append(this.KMLLoaderTab);
37233 },
37234
37235 addKMZLoader : function() {
37236 $(this.parent.gui.loaderTypeSelect).append("<option value='KMZLoader'>KMZ File URL</option>");
37237
37238 this.KMZLoaderTab = document.createElement("div");
37239 $(this.KMZLoaderTab).attr("id","KMZLoader");
37240
37241 this.kmzURL = document.createElement("input");
37242 $(this.kmzURL).attr("type","text");
37243 $(this.KMZLoaderTab).append(this.kmzURL);
37244
37245 this.loadKMZButton = document.createElement("button");
37246 $(this.loadKMZButton).text("load KMZ");
37247 $(this.KMZLoaderTab).append(this.loadKMZButton);
37248
37249 $(this.loadKMZButton).click($.proxy(function(){
37250
37251 var dataLoader = this;
37252
37253 var kmzURL = $(this.kmzURL).val();
37254 if (kmzURL.length === 0)
37255 return;
37256 var origURL = kmzURL;
37257 var fileName = dataLoader.getFileName(kmzURL);
37258 if (typeof this.options.proxy != 'undefined')
37259 kmzURL = this.options.proxy + kmzURL;
37260
37261 GeoTemConfig.getKmz(kmzURL, function(kmlArray){
37262 $(kmlArray).each(function(){
37263 var dataSet = new Dataset(GeoTemConfig.loadKml(this), fileName, origURL);
37264
37265 if (dataSet != null)
37266 dataLoader.distributeDataset(dataSet);
37267 });
37268 });
37269 },this));
37270
37271 $(this.parent.gui.loaders).append(this.KMZLoaderTab);
37272 },
37273
37274 addCSVLoader : function() {
37275 $(this.parent.gui.loaderTypeSelect).append("<option value='CSVLoader'>CSV File URL</option>");
37276
37277 this.CSVLoaderTab = document.createElement("div");
37278 $(this.CSVLoaderTab).attr("id","CSVLoader");
37279
37280 this.csvURL = document.createElement("input");
37281 $(this.csvURL).attr("type","text");
37282 $(this.CSVLoaderTab).append(this.csvURL);
37283
37284 this.loadCSVButton = document.createElement("button");
37285 $(this.loadCSVButton).text("load CSV");
37286 $(this.CSVLoaderTab).append(this.loadCSVButton);
37287
37288 $(this.loadCSVButton).click($.proxy(function(){
37289 var dataLoader = this;
37290
37291 var csvURL = $(this.csvURL).val();
37292 if (csvURL.length === 0)
37293 return;
37294 var origURL = csvURL;
37295 var fileName = dataLoader.getFileName(csvURL);
37296 if (typeof this.options.proxy != 'undefined')
37297 csvURL = this.options.proxy + csvURL;
37298 GeoTemConfig.getCsv(csvURL, function(json){
37299 if ((typeof json !== "undefined") && (json.length > 0)) {
37300 var dataSet = new Dataset(GeoTemConfig.loadJson(json), fileName, origURL);
37301
37302 if (dataSet != null)
37303 dataLoader.distributeDataset(dataSet);
37304 } else
37305 alert("Could not load file.");
37306 });
37307 },this));
37308
37309 $(this.parent.gui.loaders).append(this.CSVLoaderTab);
37310 },
37311
37312 addLocalKMLLoader : function() {
37313 $(this.parent.gui.loaderTypeSelect).append("<option value='LocalKMLLoader'>local KML File</option>");
37314
37315 this.localKMLLoaderTab = document.createElement("div");
37316 $(this.localKMLLoaderTab).attr("id","LocalKMLLoader");
37317
37318 this.kmlFile = document.createElement("input");
37319 $(this.kmlFile).attr("type","file");
37320 $(this.localKMLLoaderTab).append(this.kmlFile);
37321
37322 this.loadLocalKMLButton = document.createElement("button");
37323 $(this.loadLocalKMLButton).text("load KML");
37324 $(this.localKMLLoaderTab).append(this.loadLocalKMLButton);
37325
37326 $(this.loadLocalKMLButton).click($.proxy(function(){
37327 var filelist = $(this.kmlFile).get(0).files;
37328 if (filelist.length > 0){
37329 var file = filelist[0];
37330 var fileName = file.name;
37331 var reader = new FileReader();
37332
37333 reader.onloadend = ($.proxy(function(theFile) {
37334 return function(e) {
37335 var dataSet = new Dataset(GeoTemConfig.loadKml($.parseXML(reader.result)), fileName);
37336 if (dataSet != null)
37337 this.distributeDataset(dataSet);
37338 };
37339 }(file),this));
37340
37341 reader.readAsText(file);
37342 }
37343 },this));
37344
37345 $(this.parent.gui.loaders).append(this.localKMLLoaderTab);
37346 },
37347
37348 addLocalCSVLoader : function() {
37349 $(this.parent.gui.loaderTypeSelect).append("<option value='LocalCSVLoader'>local CSV File</option>");
37350
37351 this.localCSVLoaderTab = document.createElement("div");
37352 $(this.localCSVLoaderTab).attr("id","LocalCSVLoader");
37353
37354 this.csvFile = document.createElement("input");
37355 $(this.csvFile).attr("type","file");
37356 $(this.localCSVLoaderTab).append(this.csvFile);
37357
37358 this.loadLocalCSVButton = document.createElement("button");
37359 $(this.loadLocalCSVButton).text("load CSV");
37360 $(this.localCSVLoaderTab).append(this.loadLocalCSVButton);
37361
37362 $(this.loadLocalCSVButton).click($.proxy(function(){
37363 var filelist = $(this.csvFile).get(0).files;
37364 if (filelist.length > 0){
37365 var file = filelist[0];
37366 var fileName = file.name;
37367 var reader = new FileReader();
37368
37369 reader.onloadend = ($.proxy(function(theFile) {
37370 return function(e) {
37371 var json = GeoTemConfig.convertCsv(reader.result);
37372 var dataSet = new Dataset(GeoTemConfig.loadJson(json), fileName);
37373 if (dataSet != null)
37374 this.distributeDataset(dataSet);
37375 };
37376 }(file),this));
37377
37378 reader.readAsText(file);
37379 }
37380 },this));
37381
37382 $(this.parent.gui.loaders).append(this.localCSVLoaderTab);
37383 },
37384
37385 addLocalStorageLoader : function() {
37386 var dataLoader = this;
37387 this.localStorageLoaderTab = document.createElement("div");
37388 $(this.localStorageLoaderTab).attr("id","LocalStorageLoader");
37389
37390 var localDatasets = document.createElement("select");
37391 $(this.localStorageLoaderTab).append(localDatasets);
37392
37393 var localStorageDatasetCount = 0;
37394 for(var key in localStorage){
37395 //TODO: this is a somewhat bad idea, as it is used in multiple widgets.
37396 //A global GeoTemCo option "prefix" could be better. But still..
37397 if (key.startsWith("GeoBrowser_dataset_")){
37398 localStorageDatasetCount++;
37399 var label = key.substring("GeoBrowser_dataset_".length);
37400 var url = key;
37401 $(localDatasets).append("<option value='"+url+"'>"+decodeURIComponent(label)+"</option>");
37402 }
37403 }
37404
37405 //only show if there are datasets
37406 if (localStorageDatasetCount > 0)
37407 $(this.parent.gui.loaderTypeSelect).append("<option value='LocalStorageLoader'>browser storage</option>");
37408
37409 this.loadLocalStorageButton = document.createElement("button");
37410 $(this.loadLocalStorageButton).text("load");
37411 $(this.localStorageLoaderTab).append(this.loadLocalStorageButton);
37412
37413 $(this.loadLocalStorageButton).click($.proxy(function(){
37414 var fileKey = $(localDatasets).find(":selected").attr("value");
37415 if (fileKey.length === 0)
37416 return;
37417 var csv = $.remember({name:fileKey});
37418 //TODO: this is a somewhat bad idea, as it is used in multiple widgets.
37419 //A global GeoTemCo option "prefix" could be better. But still..
37420 var fileName = decodeURIComponent(fileKey.substring("GeoBrowser_dataset_".length));
37421 var json = GeoTemConfig.convertCsv(csv);
37422 var dataSet = new Dataset(GeoTemConfig.loadJson(json), fileName, fileKey, "local");
37423 if (dataSet != null)
37424 dataLoader.distributeDataset(dataSet);
37425 },this));
37426
37427 $(this.parent.gui.loaders).append(this.localStorageLoaderTab);
37428 }
37429 };
37430 /*
37431 * DataloaderConfig.js
37432 *
37433 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
37434 *
37435 * This library is free software; you can redistribute it and/or
37436 * modify it under the terms of the GNU Lesser General Public
37437 * License as published by the Free Software Foundation; either
37438 * version 3 of the License, or (at your option) any later version.
37439 *
37440 * This library is distributed in the hope that it will be useful,
37441 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37442 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37443 * Lesser General Public License for more details.
37444 *
37445 * You should have received a copy of the GNU Lesser General Public
37446 * License along with this library; if not, write to the Free Software
37447 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37448 * MA 02110-1301 USA
37449 */
37450
37451 /**
37452 * @class DataloaderConfig
37453 * Dataloader Configuration File
37454 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
37455 */
37456 function DataloaderConfig(options) {
37457
37458 this.options = {
37459 proxy : 'php/proxy.php?address=',
37460 staticKML : [
37461 // {header: "header label"},
37462 // {label: "Johann Wolfgang von Goethe", url:"http://.../goethe.kml" },
37463 ]
37464 };
37465 if ( typeof options != 'undefined') {
37466 $.extend(this.options, options);
37467 }
37468
37469 };
37470 /*
37471 * DataloaderGui.js
37472 *
37473 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
37474 *
37475 * This library is free software; you can redistribute it and/or
37476 * modify it under the terms of the GNU Lesser General Public
37477 * License as published by the Free Software Foundation; either
37478 * version 3 of the License, or (at your option) any later version.
37479 *
37480 * This library is distributed in the hope that it will be useful,
37481 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37482 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37483 * Lesser General Public License for more details.
37484 *
37485 * You should have received a copy of the GNU Lesser General Public
37486 * License along with this library; if not, write to the Free Software
37487 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37488 * MA 02110-1301 USA
37489 */
37490
37491 /**
37492 * @class DataloaderGui
37493 * Dataloader GUI Implementation
37494 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
37495 *
37496 * @param {DataloaderWidget} parent Dataloader widget object
37497 * @param {HTML object} div parent div to append the Dataloader gui
37498 * @param {JSON} options Dataloader configuration
37499 */
37500 function DataloaderGui(dataloader, div, options) {
37501
37502 var dataloaderGui = this;
37503
37504 this.dataloaderContainer = div;
37505 this.dataloaderContainer.style.position = 'relative';
37506
37507 this.loaderTypeSelect = document.createElement("select");
37508 div.appendChild(this.loaderTypeSelect);
37509
37510 this.loaders = document.createElement("div");
37511 div.appendChild(this.loaders);
37512
37513 $(this.loaderTypeSelect).change(function(){
37514 var activeLoader = $(this).val();
37515 $(dataloaderGui.loaders).find("div").each(function(){
37516 if ($(this).attr("id") == activeLoader)
37517 $(this).show();
37518 else
37519 $(this).hide();
37520 });
37521 });
37522 };
37523 /*
37524 * DataloaderWidget.js
37525 *
37526 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
37527 *
37528 * This library is free software; you can redistribute it and/or
37529 * modify it under the terms of the GNU Lesser General Public
37530 * License as published by the Free Software Foundation; either
37531 * version 3 of the License, or (at your option) any later version.
37532 *
37533 * This library is distributed in the hope that it will be useful,
37534 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37535 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37536 * Lesser General Public License for more details.
37537 *
37538 * You should have received a copy of the GNU Lesser General Public
37539 * License along with this library; if not, write to the Free Software
37540 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37541 * MA 02110-1301 USA
37542 */
37543
37544 /**
37545 * @class DataloaderWidget
37546 * DataloaderWidget Implementation
37547 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
37548 *
37549 * @param {WidgetWrapper} core wrapper for interaction to other widgets
37550 * @param {HTML object} div parent div to append the Dataloader widget div
37551 * @param {JSON} options user specified configuration that overwrites options in DataloaderConfig.js
37552 */
37553 DataloaderWidget = function(core, div, options) {
37554
37555 this.core = core;
37556 this.core.setWidget(this);
37557
37558 this.options = (new DataloaderConfig(options)).options;
37559 this.gui = new DataloaderGui(this, div, this.options);
37560
37561 this.dataLoader = new Dataloader(this);
37562 }
37563
37564 DataloaderWidget.prototype = {
37565
37566 initWidget : function() {
37567
37568 var dataloaderWidget = this;
37569 },
37570
37571 highlightChanged : function(objects) {
37572 if( !GeoTemConfig.highlightEvents ){
37573 return;
37574 }
37575 },
37576
37577 selectionChanged : function(selection) {
37578 if( !GeoTemConfig.selectionEvents ){
37579 return;
37580 }
37581 },
37582
37583 triggerHighlight : function(item) {
37584 },
37585
37586 tableSelection : function() {
37587 },
37588
37589 deselection : function() {
37590 },
37591
37592 filtering : function() {
37593 },
37594
37595 inverseFiltering : function() {
37596 },
37597
37598 triggerRefining : function() {
37599 },
37600
37601 reset : function() {
37602 },
37603
37604 loadFromURL : function() {
37605 var dataLoaderWidget = this;
37606 //using jQuery-URL-Parser (https://github.com/skruse/jQuery-URL-Parser)
37607 var datasets = [];
37608 $.each($.url().param(),function(paramName, paramValue){
37609 //startsWith and endsWith defined in SIMILE Ajax (string.js)
37610 var fileName = dataLoaderWidget.dataLoader.getFileName(paramValue);
37611 var origURL = paramValue;
37612 if (typeof dataLoaderWidget.options.proxy != 'undefined')
37613 paramValue = dataLoaderWidget.options.proxy + paramValue;
37614 if (paramName.toLowerCase().startsWith("kml")){
37615 var kmlDoc = GeoTemConfig.getKml(paramValue);
37616 var dataSet = new Dataset(GeoTemConfig.loadKml(kmlDoc), fileName, origURL);
37617 if (dataSet != null)
37618 datasets.push(dataSet);
37619 }
37620 else if (paramName.toLowerCase().startsWith("csv")){
37621 var json = GeoTemConfig.getCsv(paramValue);
37622 var dataSet = new Dataset(GeoTemConfig.loadJson(json), fileName, origURL);
37623 if (dataSet != null)
37624 datasets.push(dataSet);
37625 }
37626 else if (paramName.toLowerCase().startsWith("local")){
37627 var csv = $.remember({name:encodeURIComponent(origURL)});
37628 //TODO: this is a bad idea and will be changed upon having a better
37629 //usage model for local stored data
37630 var fileName = origURL.substring("GeoBrowser_dataset_".length);
37631 var json = GeoTemConfig.convertCsv(csv);
37632 var dataSet = new Dataset(GeoTemConfig.loadJson(json), fileName, origURL, "local");
37633 if (dataSet != null)
37634 datasets.push(dataSet);
37635 }
37636 });
37637 //Load the (optional!) dataset colors
37638 $.each($.url().param(),function(paramName, paramValue){
37639 if (paramName.toLowerCase().startsWith("color")){
37640 //color is 1-based, index is 0-based!
37641 var datasetID = parseInt(paramName.substring("color".length))-1;
37642 if (datasets.length > datasetID){
37643 if (typeof datasets[datasetID].color === "undefined"){
37644 var color = new Object();
37645 var colorsSelectedUnselected = paramValue.split(",");
37646 if (colorsSelectedUnselected.length > 2)
37647 return;
37648
37649 var color1 = colorsSelectedUnselected[0];
37650 if (color1.length != 6)
37651 return;
37652
37653 color.r1 = parseInt(color1.substr(0,2),16);
37654 color.g1 = parseInt(color1.substr(2,2),16);
37655 color.b1 = parseInt(color1.substr(4,2),16);
37656
37657 //check if a unselected color is given
37658 if (colorsSelectedUnselected.length == 2){
37659 var color0 = colorsSelectedUnselected[1];
37660 if (color0.length != 6)
37661 return;
37662
37663 color.r0 = parseInt(color0.substr(0,2),16);
37664 color.g0 = parseInt(color0.substr(2,2),16);
37665 color.b0 = parseInt(color0.substr(4,2),16);
37666 } else {
37667 //if not: use the selected color "halved"
37668 color.r0 = Math.round(color.r1/2);
37669 color.g0 = Math.round(color.g1/2);
37670 color.b0 = Math.round(color.b1/2);
37671 }
37672
37673 datasets[datasetID].color = color;
37674 }
37675 }
37676 }
37677 });
37678 if (datasets.length > 0)
37679 dataLoaderWidget.dataLoader.distributeDatasets(datasets);
37680 }
37681 };
37682 /*
37683 * FuzzyTimelineConfig.js
37684 *
37685 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
37686 *
37687 * This library is free software; you can redistribute it and/or
37688 * modify it under the terms of the GNU Lesser General Public
37689 * License as published by the Free Software Foundation; either
37690 * version 3 of the License, or (at your option) any later version.
37691 *
37692 * This library is distributed in the hope that it will be useful,
37693 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37694 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37695 * Lesser General Public License for more details.
37696 *
37697 * You should have received a copy of the GNU Lesser General Public
37698 * License along with this library; if not, write to the Free Software
37699 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37700 * MA 02110-1301 USA
37701 */
37702
37703 /**
37704 * @class FuzzyTimelineConfig
37705 * FuzzyTimeline Configuration File
37706 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
37707 */
37708 function FuzzyTimelineConfig(options) {
37709
37710 this.options = {
37711 proxy : 'php/proxy.php?address=',
37712 //TODO: experiment with number of ticks, 150 seems to be ok for now
37713 maxBars : 50,
37714 maxDensityTicks : 150,
37715 /*drawing modes:
37716 * fuzzy - weight is distributed over all spans an object overlaps, so that the sum remains the weight,
37717 * stacking - every span that on object overlaps gets the complete weight (limited by the amount the span is overlapped, e.g. first span and last might get less)
37718 */
37719 timelineMode : 'stacking',
37720 showRangePiechart : false,
37721 backgroundColor : "#EEEEEE",
37722 showYAxis : true,
37723 //whether time-spans that "enlargen" the plot are allowed
37724 //if set to true, a span that creates more "bars" than fit on the screen
37725 //will lead to a width-increase of the chart (and a scroll bar appears)
37726 showAllPossibleSpans : true,
37727 };
37728 if ( typeof options != 'undefined') {
37729 $.extend(this.options, options);
37730 }
37731
37732 };
37733 /*
37734 * FuzzyTimelineDensity.js
37735 *
37736 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
37737 *
37738 * This library is free software; you can redistribute it and/or
37739 * modify it under the terms of the GNU Lesser General Public
37740 * License as published by the Free Software Foundation; either
37741 * version 3 of the License, or (at your option) any later version.
37742 *
37743 * This library is distributed in the hope that it will be useful,
37744 * but WITHOUT ANY WARRANTY; without even the implied warranty of
37745 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37746 * Lesser General Public License for more details.
37747 *
37748 * You should have received a copy of the GNU Lesser General Public
37749 * License along with this library; if not, write to the Free Software
37750 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
37751 * MA 02110-1301 USA
37752 */
37753
37754 /**
37755 * @class FuzzyTimelineDensity
37756 * Implementation for a fuzzy time-ranges density plot
37757 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
37758 *
37759 * @param {HTML object} parent div to append the FuzzyTimeline
37760 */
37761 function FuzzyTimelineDensity(parent,div) {
37762
37763 this.index;
37764 this.fuzzyTimeline = this;
37765 this.singleTickWidth;
37766 this.singleTickCenter = function(){return this.singleTickWidth/2;};
37767 //contains all data
37768 this.datasetsPlot;
37769 this.datasetsHash;
37770 this.highlightedDatasetsPlot;
37771 this.yValMin;
37772 this.yValMax;
37773 this.displayType;
37774 //contains selected data
37775 this.selected = undefined;
37776 //contains the last selected "date"
37777 this.highlighted;
37778
37779 this.parent = parent;
37780 this.div = div;
37781 this.options = parent.options;
37782 this.plot;
37783 this.maxTickCount = this.options.maxDensityTicks;
37784
37785 this.datasets;
37786 }
37787
37788 FuzzyTimelineDensity.prototype = {
37789
37790 initialize : function(datasets) {
37791 var density = this;
37792
37793 density.datasets = datasets;
37794 density.selected = [];
37795 },
37796
37797 createPlot : function(data){
37798 density = this;
37799 var chartData = [];
37800
37801 chartData.push([density.parent.overallMin,0]);
37802 $.each(data, function(name,val){
37803 var tickCenterTime = density.parent.overallMin+name*density.singleTickWidth+density.singleTickCenter();
37804 var dateObj = moment(tickCenterTime);
37805 chartData.push([dateObj,val]);
37806 });
37807 var maxPlotedDate = chartData[chartData.length-1][0];
37808 if (density.parent.overallMax > maxPlotedDate){
37809 chartData.push([density.parent.overallMax,0]);
37810 } else {
37811 chartData.push([maxPlotedDate+1,0]);
37812 }
37813
37814
37815
37816 return chartData;
37817 },
37818
37819 //uniform distribution (UD)
37820 createUDData : function(datasets) {
37821 var density = this;
37822 var plots = [];
37823 var objectHashes = [];
37824 $(datasets).each(function(){
37825 var chartDataCounter = new Object();
37826 var objectHash = new Object();
37827
37828 for (var i = 0; i < density.tickCount; i++){
37829 chartDataCounter[i]=0;
37830 }
37831 //check if we got "real" datasets, or just array of objects
37832 var datasetObjects = this;
37833 if (typeof this.objects !== "undefined")
37834 datasetObjects = this.objects;
37835 $(datasetObjects).each(function(){
37836 var ticks = density.parent.getTicks(this, density.singleTickWidth);
37837 if (typeof ticks !== "undefined"){
37838 var exactTickCount =
37839 ticks.firstTickPercentage+
37840 ticks.lastTickPercentage+
37841 (ticks.lastTick-ticks.firstTick-1);
37842 for (var i = ticks.firstTick; i <= ticks.lastTick; i++){
37843 var weight = 0;
37844 //calculate the weight for each span, that the object overlaps
37845 if (density.parent.options.timelineMode == 'fuzzy'){
37846 //in fuzzy mode, each span gets just a fraction of the complete weight
37847 if (i == ticks.firstTick)
37848 weight = this.weight * ticks.firstTickPercentage/exactTickCount;
37849 else if (i == ticks.lastTick)
37850 weight = this.weight * ticks.lastTickPercentage/exactTickCount;
37851 else
37852 weight = this.weight * 1/exactTickCount;
37853 } else if (density.parent.options.timelineMode == 'stacking'){
37854 //in stacking mode each span gets the same amount.
37855 //(besides first and last..)
37856 if (i == ticks.firstTick)
37857 weight = this.weight * ticks.firstTickPercentage;
37858 else if (i == ticks.lastTick)
37859 weight = this.weight * ticks.lastTickPercentage;
37860 else
37861 weight = this.weight;
37862
37863 weight = this.weight;
37864 }
37865
37866 chartDataCounter[i] += weight;
37867 //add this object to the hash
37868 if (typeof objectHash[i] === "undefined")
37869 objectHash[i] = [];
37870 objectHash[i].push(this);
37871 }
37872 }
37873 });
37874
37875 var udChartData = density.createPlot(chartDataCounter);
37876 if (udChartData.length > 0)
37877 plots.push(udChartData);
37878
37879 objectHashes.push(objectHash);
37880 });
37881
37882 return {plots:plots, hashs:objectHashes};
37883 },
37884
37885 showPlot : function() {
37886 var density = this;
37887 var plot = density.datasetsPlot;
37888 var highlight_select_plot = $.merge([],plot);
37889
37890 //see if there are selected/highlighted values
37891 if (density.highlightedDatasetsPlot instanceof Array){
37892 //check if plot is some other - external - graph
37893 if (plot === density.datasetsPlot)
37894 highlight_select_plot = $.merge(highlight_select_plot,density.highlightedDatasetsPlot);
37895 }
37896
37897 var axisFormatString = "%Y";
37898 var tooltipFormatString = "YYYY";
37899 if (density.singleTickWidth<60*1000){
37900 axisFormatString = "%Y/%m/%d %H:%M:%S";
37901 tooltipFormatString = "YYYY/MM/DD HH:mm:ss";
37902 } else if (density.singleTickWidth<60*60*1000) {
37903 axisFormatString = "%Y/%m/%d %H:%M";
37904 tooltipFormatString = "YYYY/MM/DD HH:mm";
37905 } else if (density.singleTickWidth<24*60*60*1000){
37906 axisFormatString = "%Y/%m/%d %H";
37907 tooltipFormatString = "YYYY/MM/DD HH";
37908 } else if (density.singleTickWidth<31*24*60*60*1000){
37909 axisFormatString = "%Y/%m/%d";
37910 tooltipFormatString = "YYYY/MM/DD";
37911 } else if (density.singleTickWidth<12*31*24*60*60*1000){
37912 axisFormatString = "%Y/%m";
37913 tooltipFormatString = "YYYY/MM";
37914 }
37915
37916 var options = {
37917 series:{
37918 lines:{show: true}
37919 },
37920 grid: {
37921 hoverable: true,
37922 clickable: true,
37923 backgroundColor: density.parent.options.backgroundColor,
37924 borderWidth: 0,
37925 minBorderMargin: 0,
37926 },
37927 legend: {
37928 },
37929 tooltip: true,
37930 tooltipOpts: {
37931 content: function(label, xval, yval, flotItem){
37932 highlightString = moment(xval-density.singleTickCenter()).format(tooltipFormatString) + " - " +
37933 moment(xval+density.singleTickCenter()).format(tooltipFormatString) + " : ";
37934 //(max.)2 Nachkomma-Stellen von y-Wert anzeigen
37935 highlightString += Math.round(yval*100)/100;
37936
37937 return highlightString;
37938 }
37939 },
37940 selection: {
37941 mode: "x"
37942 },
37943 xaxis: {
37944 mode: "time",
37945 timeformat:axisFormatString,
37946 min : density.parent.overallMin,
37947 max : density.parent.overallMax,
37948 },
37949 yaxis: {
37950 min : density.yValMin,
37951 max : density.yValMax
37952 },
37953 };
37954 if (!density.parent.options.showYAxis)
37955 options.yaxis.show=false;
37956
37957 var highlight_select_plot_colors = [];
37958 var i = 0;
37959 $(highlight_select_plot).each(function(){
37960 var color;
37961 if (i < GeoTemConfig.datasets.length){
37962 var datasetColors = GeoTemConfig.getColor(i);
37963 if (highlight_select_plot.length>GeoTemConfig.datasets.length)
37964 color = "rgb("+datasetColors.r0+","+datasetColors.g0+","+datasetColors.b0+")";
37965 else
37966 color = "rgb("+datasetColors.r1+","+datasetColors.g1+","+datasetColors.b1+")";
37967 } else {
37968 var datasetColors = GeoTemConfig.getColor(i-GeoTemConfig.datasets.length);
37969 color = "rgb("+datasetColors.r1+","+datasetColors.g1+","+datasetColors.b1+")";
37970 }
37971
37972 highlight_select_plot_colors.push({
37973 color : color,
37974 data : this
37975 });
37976 i++;
37977 });
37978
37979 density.plot = $.plot($(density.div), highlight_select_plot_colors, options);
37980 density.parent.drawHandles();
37981
37982 var rangeBars = density.parent.rangeBars;
37983 if (typeof rangeBars !== "undefined")
37984 $(density.div).unbind("plothover", rangeBars.hoverFunction);
37985 $(density.div).unbind("plothover", density.hoverFunction);
37986 $(density.div).bind("plothover", density.hoverFunction);
37987
37988 //this var prevents the execution of the plotclick event after a select event
37989 density.wasSelection = false;
37990 $(density.div).unbind("plotclick");
37991 $(density.div).bind("plotclick", density.clickFunction);
37992
37993 $(density.div).unbind("plotselected");
37994 $(density.div).bind("plotselected", density.selectFuntion);
37995 },
37996
37997 hoverFunction : function (event, pos, item) {
37998 var hoverPoint;
37999 //TODO: this could be wanted (if negative weight is used)
38000 if ((item)&&(item.datapoint[1] != 0)) {
38001 //at begin and end of plot there are added 0 points
38002 hoverPoint = item.dataIndex-1;
38003 }
38004 //remember last point, so that we don't redraw the current state
38005 //that "hoverPoint" may be undefined is on purpose
38006 if (density.highlighted !== hoverPoint){
38007 density.highlighted = hoverPoint;
38008 density.triggerHighlight(hoverPoint);
38009 }
38010 },
38011
38012 clickFunction : function (event, pos, item) {
38013 if (density.wasSelection)
38014 density.wasSelection = false;
38015 else {
38016 //remove selection handles (if there were any)
38017 density.parent.clearHandles();
38018
38019 var selectPoint;
38020 //that date may be undefined is on purpose
38021 //TODO: ==0 could be wanted (if negative weight is used)
38022 if ((item)&&(item.datapoint[1] != 0)) {
38023 //at begin and end of plot there are added 0 points
38024 selectPoint = item.dataIndex-1;
38025 }
38026 density.triggerSelection(selectPoint);
38027 }
38028 },
38029
38030 selectFuntion : function(event, ranges) {
38031 var spanArray = density.parent.getSpanArray(density.singleTickWidth);
38032 var startSpan, endSpan;
38033 for (var i = 0; i < spanArray.length-1; i++){
38034 if ((typeof startSpan === "undefined") && (ranges.xaxis.from <= spanArray[i+1]))
38035 startSpan = i;
38036 if ((typeof endSpan === "undefined") && (ranges.xaxis.to <= spanArray[i+1]))
38037 endSpan = i;
38038 }
38039
38040 if ((typeof startSpan !== "undefined") && (typeof endSpan !== "undefined")){
38041 density.triggerSelection(startSpan, endSpan);
38042 density.wasSelection = true;
38043
38044 density.parent.clearHandles();
38045 var xaxis = density.plot.getAxes().xaxis;
38046 var x1 = density.plot.pointOffset({x:ranges.xaxis.from,y:0}).left;
38047 var x2 = density.plot.pointOffset({x:ranges.xaxis.to,y:0}).left;
38048
38049 density.parent.addHandle(x1,x2);
38050 }
38051 },
38052
38053 selectByX : function(x1, x2){
38054 density = this;
38055 var xaxis = density.plot.getAxes().xaxis;
38056 var offset = density.plot.getPlotOffset().left;
38057 var from = xaxis.c2p(x1-offset);
38058 var to = xaxis.c2p(x2-offset);
38059
38060 var spanArray = density.parent.getSpanArray(density.singleTickWidth);
38061 var startSpan, endSpan;
38062 for (var i = 0; i < spanArray.length-1; i++){
38063 if ((typeof startSpan === "undefined") && (from <= spanArray[i+1]))
38064 startSpan = i;
38065 if ((typeof endSpan === "undefined") && (to <= spanArray[i+1]))
38066 endSpan = i;
38067 }
38068
38069 if ((typeof startSpan !== "undefined") && (typeof endSpan !== "undefined")){
38070 density.triggerSelection(startSpan, endSpan);
38071 }
38072 },
38073
38074 drawDensityPlot : function(datasets, tickWidth) {
38075 var density = this;
38076 //calculate tick width (will be in ms)
38077 delete density.tickCount;
38078 delete density.singleTickWidth;
38079 delete density.highlightedDatasetsPlot;
38080 density.parent.zoomPlot(1);
38081 if (typeof tickWidth !== "undefined"){
38082 density.singleTickWidth = tickWidth;
38083 density.tickCount = Math.ceil((density.parent.overallMax-density.parent.overallMin)/tickWidth);
38084 }
38085 if ((typeof density.tickCount === "undefined") || (density.tickCount > density.maxTickCount)){
38086 density.tickCount = density.maxTickCount;
38087 density.singleTickWidth = (density.parent.overallMax-density.parent.overallMin)/density.tickCount;
38088 if (density.singleTickWidth === 0)
38089 density.singleTickWidth = 1;
38090 }
38091
38092 var hashAndPlot = density.createUDData(datasets);
38093
38094 density.datasetsPlot = hashAndPlot.plots;
38095 density.datasetsHash = hashAndPlot.hashs;
38096
38097 density.yValMin = 0;
38098 density.yValMax = 0;
38099
38100 density.combinedDatasetsPlot = [];
38101 for (var i = 0; i < density.datasetsPlot.length; i++){
38102 for (var j = 0; j < density.datasetsPlot[i].length; j++){
38103 var val = density.datasetsPlot[i][j][1];
38104
38105 if (val < density.yValMin)
38106 density.yValMin = val;
38107 if (val > density.yValMax)
38108 density.yValMax = val;
38109 }
38110 }
38111
38112 density.showPlot();
38113 },
38114
38115 triggerHighlight : function(hoverPoint) {
38116 var density = this;
38117 var highlightedObjects = [];
38118
38119
38120 if (typeof hoverPoint !== "undefined") {
38121 $(density.datasetsHash).each(function(){
38122 if (typeof this[hoverPoint] !== "undefined")
38123 highlightedObjects.push(this[hoverPoint]);
38124 else
38125 highlightedObjects.push([]);
38126 });
38127 } else {
38128 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
38129 highlightedObjects.push([]);
38130 }
38131 this.parent.core.triggerHighlight(highlightedObjects);
38132 },
38133
38134 triggerSelection : function(startPoint, endPoint) {
38135 var density = this;
38136 var selection;
38137 if (typeof startPoint !== "undefined") {
38138 if (typeof endPoint === "undefined")
38139 endPoint = startPoint;
38140 density.selected = [];
38141 $(density.datasetsHash).each(function(){
38142 var objects = [];
38143 for (var i = startPoint; i <= endPoint; i++){
38144 $(this[i]).each(function(){
38145 if ($.inArray(this, objects) == -1){
38146 objects.push(this);
38147 }
38148 });
38149 }
38150 density.selected.push(objects);
38151 });
38152
38153 selection = new Selection(density.selected, density.parent);
38154 } else {
38155 //empty selection
38156 density.selected = [];
38157 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
38158 density.selected.push([]);
38159 selection = new Selection(density.selected);
38160 }
38161
38162 this.parent.selectionChanged(selection);
38163 this.parent.core.triggerSelection(selection);
38164 },
38165
38166 highlightChanged : function(objects) {
38167 if( !GeoTemConfig.highlightEvents ){
38168 return;
38169 }
38170 var density = this;
38171 var emptyHighlight = true;
38172 var selected_highlighted = objects;
38173 if (typeof density.selected !== "undefined")
38174 selected_highlighted = GeoTemConfig.mergeObjects(objects,density.selected);
38175 $(selected_highlighted).each(function(){
38176 if ((this instanceof Array) && (this.length > 0)){
38177 emptyHighlight = false;
38178 return false;
38179 }
38180 });
38181 if (emptyHighlight && (typeof density.selected === "undefined")){
38182 density.highlightedDatasetsPlot = [];
38183 } else {
38184 density.highlightedDatasetsPlot = density.createUDData(selected_highlighted).plots;
38185 }
38186 density.showPlot();
38187 },
38188
38189 selectionChanged : function(objects) {
38190 if( !GeoTemConfig.selectionEvents ){
38191 return;
38192 }
38193 var density = this;
38194 density.selected = objects;
38195 density.highlightChanged([]);
38196 },
38197
38198 deselection : function() {
38199 },
38200
38201 filtering : function() {
38202 },
38203
38204 inverseFiltering : function() {
38205 },
38206
38207 triggerRefining : function() {
38208 },
38209
38210 reset : function() {
38211 },
38212
38213 show : function() {
38214 },
38215
38216 hide : function() {
38217 }
38218 };
38219 /*
38220 * FuzzyTimelineGui.js
38221 *
38222 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
38223 *
38224 * This library is free software; you can redistribute it and/or
38225 * modify it under the terms of the GNU Lesser General Public
38226 * License as published by the Free Software Foundation; either
38227 * version 3 of the License, or (at your option) any later version.
38228 *
38229 * This library is distributed in the hope that it will be useful,
38230 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38231 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38232 * Lesser General Public License for more details.
38233 *
38234 * You should have received a copy of the GNU Lesser General Public
38235 * License along with this library; if not, write to the Free Software
38236 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
38237 * MA 02110-1301 USA
38238 */
38239
38240 /**
38241 * @class FuzzyTimelineGui
38242 * FuzzyTimeline GUI Implementation
38243 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
38244 *
38245 * @param {FuzzyTimelineWidget} parent FuzzyTimeline widget object
38246 * @param {HTML object} div parent div to append the FuzzyTimeline gui
38247 * @param {JSON} options FuzzyTimeline configuration
38248 */
38249 function FuzzyTimelineGui(fuzzyTimelineWidget, div, options) {
38250
38251 this.parent = fuzzyTimelineWidget;
38252 var fuzzyTimelineGui = this;
38253
38254 this.fuzzyTimelineContainer = div;
38255 //if no height is given, draw it in a 32/9 ratio
38256 if ($(this.fuzzyTimelineContainer).height() === 0)
38257 $(this.fuzzyTimelineContainer).height($(this.fuzzyTimelineContainer).width()*9/32);
38258 //this.fuzzyTimelineContainer.style.position = 'relative';
38259
38260 this.sliderTable = document.createElement("table");
38261 $(this.sliderTable).addClass("ddbToolbar");
38262 $(this.sliderTable).width("100%");
38263 $(this.sliderTable).height("49px");
38264 div.appendChild(this.sliderTable);
38265
38266 this.plotDIVHeight = $(this.fuzzyTimelineContainer).height()-$(this.sliderTable).height();
38267 var plotScrollContainer = $("<div></div>");
38268 plotScrollContainer.css("overflow-x","auto");
38269 plotScrollContainer.css("overflow-y","hidden");
38270 plotScrollContainer.width("100%");
38271 plotScrollContainer.height(this.plotDIVHeight);
38272 $(div).append(plotScrollContainer);
38273 this.plotDiv = document.createElement("div");
38274 $(this.plotDiv).width("100%");
38275 $(this.plotDiv).height(this.plotDIVHeight);
38276 plotScrollContainer.append(this.plotDiv);
38277 if (this.parent.options.showRangePiechart){
38278 this.rangePiechartDiv = document.createElement("div");
38279 $(this.rangePiechartDiv).css("float","right");
38280 //alter plot div width (leave space for piechart)
38281 $(this.plotDiv).width("75%");
38282 $(this.rangePiechartDiv).width("25%");
38283 $(this.rangePiechartDiv).height(plotDIVHeight);
38284 div.appendChild(this.rangePiechartDiv);
38285 }
38286 };
38287
38288 FuzzyTimelineGui.prototype = {
38289 };
38290 /*
38291 * FuzzyTimelineRangeBars.js
38292 *
38293 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
38294 *
38295 * This library is free software; you can redistribute it and/or
38296 * modify it under the terms of the GNU Lesser General Public
38297 * License as published by the Free Software Foundation; either
38298 * version 3 of the License, or (at your option) any later version.
38299 *
38300 * This library is distributed in the hope that it will be useful,
38301 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38302 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38303 * Lesser General Public License for more details.
38304 *
38305 * You should have received a copy of the GNU Lesser General Public
38306 * License along with this library; if not, write to the Free Software
38307 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
38308 * MA 02110-1301 USA
38309 */
38310
38311 /**
38312 * @class FuzzyTimelineRangeBars
38313 * Implementation for a fuzzy time-ranges barchart
38314 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
38315 *
38316 * @param {HTML object} parent div to append the FuzzyTimeline
38317 */
38318 function FuzzyTimelineRangeBars(parent) {
38319
38320 this.rangeBars = this;
38321
38322 this.parent = parent;
38323 this.options = parent.options;
38324
38325 this.datasets;
38326 //contains selected data
38327 this.selected = undefined;
38328
38329 this.datasetsPlot;
38330 this.highlightedDatasetsPlot;
38331 this.yValMin;
38332 this.yValMax;
38333 this.displayType;
38334
38335 this.plotDiv = this.parent.gui.plotDiv;
38336
38337 this.spanWidth;
38338 this.tickSpans;
38339 this.plot;
38340 }
38341
38342 FuzzyTimelineRangeBars.prototype = {
38343
38344 initialize : function(datasets) {
38345 var rangeBar = this;
38346
38347 rangeBar.datasets = datasets;
38348 rangeBar.selected = [];
38349 },
38350
38351 createPlot : function(datasets) {
38352 var rangeBar = this;
38353 var plots = [];
38354 var objectHashes = [];
38355
38356 //-1 because last span is always empty (only there to have the ending date)
38357 var tickCount = rangeBar.tickSpans.length-1;
38358
38359 $(datasets).each(function(){
38360 var chartDataCounter = [];
38361 var objectHash = new Object();
38362
38363 for (var i = 0; i < tickCount; i++){
38364 chartDataCounter[i] = [];
38365 chartDataCounter[i][0]=i;
38366 chartDataCounter[i][1]=0;
38367 }
38368 //check if we got "real" datasets, or just array of objects
38369 var datasetObjects = this;
38370 if (typeof this.objects !== "undefined")
38371 datasetObjects = this.objects;
38372 $(datasetObjects).each(function(){
38373 var ticks = rangeBar.parent.getTicks(this, rangeBar.spanWidth);
38374 if (typeof ticks !== "undefined"){
38375 var exactTickCount =
38376 ticks.firstTickPercentage+
38377 ticks.lastTickPercentage+
38378 (ticks.lastTick-ticks.firstTick-1);
38379 for (var i = ticks.firstTick; i <= ticks.lastTick; i++){
38380 var weight = 0;
38381 //calculate the weight for each span, that the object overlaps
38382 if (rangeBar.parent.options.timelineMode == 'fuzzy'){
38383 //in fuzzy mode, each span gets just a fraction of the complete weight
38384 if (i == ticks.firstTick)
38385 weight = this.weight * ticks.firstTickPercentage/exactTickCount;
38386 else if (i == ticks.lastTick)
38387 weight = this.weight * ticks.lastTickPercentage/exactTickCount;
38388 else
38389 weight = this.weight * 1/exactTickCount;
38390 } else if (rangeBar.parent.options.timelineMode == 'stacking'){
38391 //in stacking mode each span gets the same amount.
38392 //(besides first and last..)
38393 if (i == ticks.firstTick)
38394 weight = this.weight * ticks.firstTickPercentage;
38395 else if (i == ticks.lastTick)
38396 weight = this.weight * ticks.lastTickPercentage;
38397 else
38398 weight = this.weight;
38399
38400 weight = this.weight;
38401 }
38402
38403 chartDataCounter[i][1] += weight;
38404 //add this object to the hash
38405 if (typeof objectHash[i] === "undefined")
38406 objectHash[i] = [];
38407 objectHash[i].push(this);
38408 }
38409 }
38410 });
38411
38412 plots.push(chartDataCounter);
38413 objectHashes.push(objectHash);
38414 });
38415
38416 return {plots:plots, hashs:objectHashes};
38417 },
38418
38419 showPlot : function(){
38420 var rangeBar = this;
38421 var plot = rangeBar.datasetsPlot;
38422 var highlight_select_plot = $.merge([],plot);
38423
38424 //see if there are selected/highlighted values
38425 if (rangeBar.highlightedDatasetsPlot instanceof Array){
38426 //check if plot is some other - external - graph
38427 if (plot === rangeBar.datasetsPlot)
38428 highlight_select_plot = $.merge(highlight_select_plot,rangeBar.highlightedDatasetsPlot);
38429 }
38430
38431 var tickCount = rangeBar.tickSpans.length-1;
38432 var ticks = [];
38433
38434 var axisFormatString = "YYYY";
38435 if (rangeBar.spanWidth<60*1000){
38436 axisFormatString = "YYYY/MM/DD HH:mm:ss";
38437 } else if (rangeBar.spanWidth<60*60*1000) {
38438 axisFormatString = "YYYY/MM/DD HH:mm";
38439 } else if (rangeBar.spanWidth<24*60*60*1000){
38440 axisFormatString = "YYYY/MM/DD HH";
38441 } else if (rangeBar.spanWidth<31*24*60*60*1000){
38442 axisFormatString = "YYYY/MM/DD";
38443 } else if (rangeBar.spanWidth<12*31*24*60*60*1000){
38444 axisFormatString = "YYYY/MM";
38445 }
38446 //only show ~10 labels on the x-Axis (increase if zoomed)
38447 var labelModulo = Math.ceil(tickCount/(10*rangeBar.parent.zoomFactor));
38448 for (var i = 0; i < tickCount; i++){
38449 var tickLabel = "";
38450 if (i%labelModulo==0){
38451 tickLabel = rangeBar.tickSpans[i].format(axisFormatString);
38452 }
38453 while ((tickLabel.length > 1) && (tickLabel.indexOf("0")==0))
38454 tickLabel = tickLabel.substring(1);
38455 ticks[i] = [i,tickLabel];
38456 }
38457
38458 var options = {
38459 series:{
38460 bars:{show: true}
38461 },
38462 grid: {
38463 hoverable: true,
38464 clickable: true,
38465 backgroundColor: rangeBar.parent.options.backgroundColor,
38466 borderWidth: 0,
38467 minBorderMargin: 0,
38468 },
38469 xaxis: {
38470 ticks: ticks,
38471 min : 0,
38472 max : tickCount,
38473 },
38474 yaxis: {
38475 min : rangeBar.yValMin,
38476 max : rangeBar.yValMax
38477 },
38478 tooltip: true,
38479 tooltipOpts: {
38480 content: function(label, xval, yval, flotItem){
38481 var fromLabel = rangeBar.tickSpans[xval].format(axisFormatString);
38482 while ((fromLabel.length > 1) && (fromLabel.indexOf("0")==0))
38483 fromLabel = fromLabel.substring(1);
38484 var toLabel = rangeBar.tickSpans[xval+1].clone().subtract("ms",1).format(axisFormatString);
38485 while ((toLabel.length > 1) && (toLabel.indexOf("0")==0))
38486 toLabel = toLabel.substring(1);
38487 highlightString = fromLabel + " - " + toLabel + " : ";
38488 //(max.)2 Nachkomma-Stellen von y-Wert anzeigen
38489 highlightString += Math.round(yval*100)/100;
38490
38491 return highlightString;
38492 }
38493 },
38494 selection: {
38495 mode: "x"
38496 }
38497 };
38498 if (!rangeBar.parent.options.showYAxis)
38499 options.yaxis.show=false;
38500
38501 var highlight_select_plot_colors = [];
38502 var i = 0;
38503 $(highlight_select_plot).each(function(){
38504 var color;
38505 if (i < GeoTemConfig.datasets.length){
38506 var datasetColors = GeoTemConfig.getColor(i);
38507 if (highlight_select_plot.length>GeoTemConfig.datasets.length)
38508 color = "rgb("+datasetColors.r0+","+datasetColors.g0+","+datasetColors.b0+")";
38509 else
38510 color = "rgb("+datasetColors.r1+","+datasetColors.g1+","+datasetColors.b1+")";
38511 } else {
38512 var datasetColors = GeoTemConfig.getColor(i-GeoTemConfig.datasets.length);
38513 color = "rgb("+datasetColors.r1+","+datasetColors.g1+","+datasetColors.b1+")";
38514 }
38515
38516 highlight_select_plot_colors.push({
38517 color : color,
38518 data : this
38519 });
38520 i++;
38521 });
38522
38523 $(rangeBar.plotDiv).unbind();
38524 rangeBar.plot = $.plot($(rangeBar.plotDiv), highlight_select_plot_colors, options);
38525 rangeBar.parent.drawHandles();
38526
38527 var density = rangeBar.parent.density;
38528 if (typeof density !== "undefined")
38529 $(rangeBar.plotDiv).unbind("plothover", density.hoverFunction);
38530 $(rangeBar.plotDiv).unbind("plothover", rangeBar.hoverFunction);
38531 $(rangeBar.plotDiv).bind("plothover", $.proxy(rangeBar.hoverFunction,rangeBar));
38532
38533 //this var prevents the execution of the plotclick event after a select event
38534 rangeBar.wasSelection = false;
38535 $(rangeBar.plotDiv).unbind("plotclick");
38536 $(rangeBar.plotDiv).bind("plotclick", $.proxy(rangeBar.clickFunction,rangeBar));
38537
38538 $(rangeBar.plotDiv).unbind("plotselected");
38539 $(rangeBar.plotDiv).bind("plotselected", $.proxy(rangeBar.selectFunction,rangeBar));
38540 },
38541
38542 hoverFunction : function (event, pos, item) {
38543 var rangeBar = this;
38544 var hoverBar;
38545 var spans;
38546 if (item) {
38547 hoverBar = item.datapoint[0];
38548 }
38549 //remember last date, so that we don't redraw the current state
38550 //that date may be undefined is on purpose
38551 if (rangeBar.highlighted !== hoverBar){
38552 rangeBar.highlighted = hoverBar;
38553 if (typeof hoverBar === "undefined")
38554 rangeBar.triggerHighlight();
38555 else
38556 rangeBar.triggerHighlight(hoverBar);
38557 }
38558 },
38559
38560 clickFunction : function (event, pos, item) {
38561 var rangeBar = this;
38562 if (rangeBar.wasSelection)
38563 rangeBar.wasSelection = false;
38564 else {
38565 //remove selection handles (if there were any)
38566 rangeBar.parent.clearHandles();
38567
38568 var clickBar;
38569 if (item) {
38570 //contains the x-value (date)
38571 clickBar = item.datapoint[0];
38572 }
38573 if (typeof clickBar === "undefined")
38574 rangeBar.triggerSelection();
38575 else
38576 rangeBar.triggerSelection(clickBar);
38577 wasDataClick = true;
38578 }
38579 },
38580
38581 selectFunction : function(event, ranges) {
38582 var rangeBar = this;
38583 startBar = Math.floor(ranges.xaxis.from);
38584 endBar = Math.floor(ranges.xaxis.to);
38585 rangeBar.triggerSelection(startBar, endBar);
38586 rangeBar.wasSelection = true;
38587
38588 rangeBar.parent.clearHandles();
38589 var xaxis = rangeBar.plot.getAxes().xaxis;
38590 var x1 = rangeBar.plot.pointOffset({x:ranges.xaxis.from,y:0}).left;
38591 var x2 = rangeBar.plot.pointOffset({x:ranges.xaxis.to,y:0}).left;
38592 rangeBar.parent.addHandle(x1,x2);
38593 },
38594
38595 selectByX : function(x1, x2){
38596 rangeBar = this;
38597 var xaxis = rangeBar.plot.getAxes().xaxis;
38598 var offset = rangeBar.plot.getPlotOffset().left;
38599 var from = Math.floor(xaxis.c2p(x1-offset));
38600 var to = Math.floor(xaxis.c2p(x2-offset));
38601
38602 rangeBar.triggerSelection(from, to);
38603 },
38604
38605 drawRangeBarChart : function(datasets, spanWidth){
38606 var rangeBar = this;
38607 rangeBar.spanWidth = spanWidth;
38608 rangeBar.tickSpans = rangeBar.parent.getSpanArray(rangeBar.spanWidth);
38609 //-1 because last span is always empty (only there to have the ending date)
38610 var tickCount = rangeBar.tickSpans.length-1;
38611
38612 if (tickCount > rangeBar.options.maxBars){
38613 var zoomFactor = tickCount / rangeBar.options.maxBars;
38614 rangeBar.parent.zoomPlot(zoomFactor);
38615 } else
38616 rangeBar.parent.zoomPlot(1);
38617
38618 rangeBar.yValMin = 0;
38619 rangeBar.yValMax = 0;
38620
38621 var plotAndHash = rangeBar.createPlot(datasets);
38622 rangeBar.datasetsPlot = plotAndHash.plots;
38623 rangeBar.datasetsHash = plotAndHash.hashs;
38624 delete rangeBar.highlightedDatasetsPlot;
38625 //redraw selected plot to fit (possible) new scale
38626 rangeBar.selectionChanged(rangeBar.selected);
38627
38628 for (var i = 0; i < rangeBar.datasetsPlot.length; i++){
38629 for (var j = 0; j < rangeBar.datasetsPlot[i].length; j++){
38630 var val = rangeBar.datasetsPlot[i][j][1];
38631
38632 if (val < rangeBar.yValMin)
38633 rangeBar.yValMin = val;
38634 if (val > rangeBar.yValMax)
38635 rangeBar.yValMax = val;
38636 }
38637 }
38638
38639 rangeBar.showPlot();
38640 },
38641
38642 highlightChanged : function(objects) {
38643 if( !GeoTemConfig.highlightEvents ){
38644 return;
38645 }
38646 var rangeBar = this;
38647 var emptyHighlight = true;
38648 var selected_highlighted = objects;
38649 if (typeof rangeBar.selected !== "undefined")
38650 var selected_highlighted = GeoTemConfig.mergeObjects(objects,rangeBar.selected);
38651 $(selected_highlighted).each(function(){
38652 if ((this instanceof Array) && (this.length > 0)){
38653 emptyHighlight = false;
38654 return false;
38655 }
38656 });
38657 if (emptyHighlight && (typeof rangeBar.selected === "undefined")){
38658 rangeBar.highlightedDatasetsPlot = [];
38659 } else {
38660 rangeBar.highlightedDatasetsPlot = rangeBar.createPlot(selected_highlighted).plots;
38661 }
38662 rangeBar.showPlot();
38663 },
38664
38665 selectionChanged : function(objects) {
38666 if( !GeoTemConfig.selectionEvents ){
38667 return;
38668 }
38669 var rangeBar = this;
38670 rangeBar.selected = objects;
38671 rangeBar.highlightChanged([]);
38672 },
38673
38674 triggerHighlight : function(hoverPoint) {
38675 var rangeBar = this;
38676 var highlightedObjects = [];
38677
38678 if (typeof hoverPoint !== "undefined"){
38679 $(rangeBar.datasetsHash).each(function(){
38680 if (typeof this[hoverPoint] !== "undefined")
38681 highlightedObjects.push(this[hoverPoint]);
38682 else
38683 highlightedObjects.push([]);
38684 });
38685 } else {
38686 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
38687 highlightedObjects.push([]);
38688 }
38689
38690 this.parent.core.triggerHighlight(highlightedObjects);
38691 },
38692
38693 triggerSelection : function(startBar, endBar) {
38694 var rangeBar = this;
38695 var selection;
38696 if (typeof startBar !== "undefined") {
38697 if (typeof endBar === "undefined")
38698 endBar = startBar;
38699 rangeBar.selected = [];
38700 $(rangeBar.datasetsHash).each(function(){
38701 var objects = [];
38702 for (var i = startBar; i <= endBar; i++){
38703 $(this[i]).each(function(){
38704 if ($.inArray(this, objects) == -1){
38705 objects.push(this);
38706 }
38707 });
38708 }
38709 rangeBar.selected.push(objects);
38710 });
38711 selection = new Selection(rangeBar.selected, rangeBar.parent);
38712 } else {
38713 rangeBar.selected = [];
38714 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
38715 rangeBar.selected.push([]);
38716 selection = new Selection(rangeBar.selected);
38717 }
38718
38719 rangeBar.parent.selectionChanged(selection);
38720 rangeBar.parent.core.triggerSelection(selection);
38721 },
38722
38723 deselection : function() {
38724 },
38725
38726 filtering : function() {
38727 },
38728
38729 inverseFiltering : function() {
38730 },
38731
38732 triggerRefining : function() {
38733 },
38734
38735 reset : function() {
38736 },
38737
38738 show : function() {
38739 },
38740
38741 hide : function() {
38742 }
38743 };
38744 /*
38745 * FuzzyTimelineRangePiechart.js
38746 *
38747 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
38748 *
38749 * This library is free software; you can redistribute it and/or
38750 * modify it under the terms of the GNU Lesser General Public
38751 * License as published by the Free Software Foundation; either
38752 * version 3 of the License, or (at your option) any later version.
38753 *
38754 * This library is distributed in the hope that it will be useful,
38755 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38756 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
38757 * Lesser General Public License for more details.
38758 *
38759 * You should have received a copy of the GNU Lesser General Public
38760 * License along with this library; if not, write to the Free Software
38761 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
38762 * MA 02110-1301 USA
38763 */
38764
38765 /**
38766 * @class FuzzyTimelineRangePiechart
38767 * Implementation for a fuzzy time-ranges pie chart
38768 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
38769 *
38770 * @param {HTML object} parent div to append the FuzzyTimeline
38771 */
38772 function FuzzyTimelineRangePiechart(parent,div) {
38773
38774 this.fuzzyTimeline = this;
38775
38776 this.parent = parent;
38777 this.options = parent.options;
38778
38779 this.div = div;
38780
38781 this.selected = [];
38782
38783 this.maxSlices = 10;
38784 }
38785
38786 FuzzyTimelineRangePiechart.prototype = {
38787
38788 initialize : function(datasets) {
38789 var piechart = this;
38790 if (piechart.parent.showRangePiechart){
38791 piechart.datasets = datasets;
38792 piechart.drawPieChart(piechart.datasets);
38793 }
38794 },
38795
38796 drawPieChart : function(datasets){
38797 var piechart = this;
38798 //build hashmap of spans (span length -> objects[])
38799 var spans = [];
38800 var index = 0;
38801 $(datasets).each(function(){
38802 var objects = this;
38803 //check whether we got "real" dataset or just a set of DataObjects
38804 if (typeof objects.objects !== "undefined")
38805 objects = objects.objects;
38806 $(objects).each(function(){
38807 var dataObject = this;
38808 var span;
38809 if (dataObject.isTemporal){
38810 span = SimileAjax.DateTime.MILLISECOND;
38811 } else if (dataObject.isFuzzyTemporal){
38812 span = dataObject.TimeSpanGranularity;
38813 }
38814
38815 if (typeof span === "undefined")
38816 return;
38817
38818 var found = false;
38819 $(spans).each(function(){
38820 if (this.span === span){
38821 this.objects[index].push(dataObject);
38822 found = true;
38823 return false;
38824 }
38825 });
38826 if (found === false){
38827 var newObjectSet = [];
38828 for (var i = 0; i < piechart.datasets.length; i++)
38829 newObjectSet.push([]);
38830 newObjectSet[index].push(dataObject);
38831 spans.push({span:span,objects:newObjectSet});
38832 }
38833 });
38834 index++;
38835 });
38836
38837 //TODO: join elements of span array to keep below certain threshold
38838
38839 //sort array by span length
38840 spans.sort(function(a,b){
38841 return(a.span-b.span);
38842 });
38843
38844 //create chart data
38845 var chartData = [];
38846 $(spans).each(function(){
38847 var spanElem = this;
38848 $(spanElem.objects).each(function(){
38849 var label = "unknown";
38850
38851 if (spanElem.span === SimileAjax.DateTime.MILLENNIUM){
38852 label = "millenia";
38853 } else if (spanElem.span === SimileAjax.DateTime.DECADE){
38854 label = "decades";
38855 } else if (spanElem.span === SimileAjax.DateTime.CENTURY){
38856 label = "centuries";
38857 } else if (spanElem.span === SimileAjax.DateTime.YEAR){
38858 label = "years";
38859 } else if (spanElem.span === SimileAjax.DateTime.MONTH){
38860 label = "months";
38861 } else if (spanElem.span === SimileAjax.DateTime.DAY){
38862 label = "days";
38863 } else if (spanElem.span === SimileAjax.DateTime.HOUR){
38864 label = "hours";
38865 } else if (spanElem.span === SimileAjax.DateTime.MINUTE){
38866 label = "minutes";
38867 } else if (spanElem.span === SimileAjax.DateTime.SECOND){
38868 label = "seconds";
38869 } else if (spanElem.span === SimileAjax.DateTime.MILLISECOND){
38870 label = "milliseconds";
38871 }
38872
38873 chartData.push({label:label,data:this.length});
38874 });
38875 });
38876
38877 $(piechart.div).unbind("plotclick");
38878 $(piechart.div).unbind("plothover");
38879 $(piechart.div).empty();
38880 if (spans.length === 0){
38881 //TODO: language specific message
38882 $(piechart.div).append("empty selection");
38883 } else {
38884 $.plot($(piechart.div), chartData,
38885 {
38886 series: {
38887 // Make this a pie chart.
38888 pie: {
38889 show:true
38890 }
38891 },
38892 legend: { show:false},
38893 grid: {
38894 hoverable: true,
38895 clickable: true
38896 },
38897 tooltip: true,
38898 }
38899 );
38900
38901 var lastHighlighted;
38902 var hoverFunction = function (event, pos, item) {
38903 if (item) {
38904 var highlightedSpan = Math.ceil(item.seriesIndex/piechart.datasets.length);
38905 if (lastHighlighted !== highlightedSpan){
38906 var highlightedObjects = [];
38907 for(;highlightedSpan>=0;highlightedSpan--){
38908 highlightedObjects = GeoTemConfig.mergeObjects(highlightedObjects,spans[highlightedSpan].objects);
38909 }
38910 lastHighlighted = highlightedSpan;
38911 }
38912 piechart.triggerHighlight(highlightedObjects);
38913 } else {
38914 piechart.triggerHighlight([]);
38915 }
38916 };
38917 $(piechart.div).bind("plothover", hoverFunction);
38918
38919 $(piechart.div).bind("plotclick", function (event, pos, item) {
38920 $(piechart.div).unbind("plothover");
38921 if (item){
38922 var selectedSpan = Math.ceil(item.seriesIndex/piechart.datasets.length);
38923 var selectedObjects = [];
38924 for(;selectedSpan>=0;selectedSpan--){
38925 selectedObjects = GeoTemConfig.mergeObjects(selectedObjects,spans[selectedSpan].objects);
38926 }
38927 piechart.triggerSelection(selectedObjects);
38928 } else {
38929 //if it was a click outside of the pie-chart, enable highlight events
38930 $(piechart.div).bind("plothover", hoverFunction);
38931 //return to old state
38932 piechart.triggerSelection(piechart.selected);
38933 //and redraw piechart
38934 piechart.highlightChanged([]);
38935 }
38936 });
38937 }
38938 },
38939
38940 highlightChanged : function(objects) {
38941 var piechart = this;
38942 if (piechart.parent.showRangePiechart){
38943 //check if this is an empty highlight
38944 var emptyHighlight = true;
38945 $(objects).each(function(){
38946 if ((this instanceof Array) && (this.length > 0)){
38947 emptyHighlight = false;
38948 return false;
38949 }
38950 });
38951
38952 if (emptyHighlight === false)
38953 piechart.drawPieChart(GeoTemConfig.mergeObjects(piechart.selected, objects));
38954 else{
38955 //return to selection (or all objects, if no selection is active)
38956 if (piechart.selected.length > 0)
38957 piechart.drawPieChart(piechart.selected);
38958 else
38959 piechart.drawPieChart(piechart.datasets);
38960 }
38961 }
38962 },
38963
38964 selectionChanged : function(selection) {
38965 var piechart = this;
38966 if (piechart.parent.showRangePiechart){
38967 if( !GeoTemConfig.selectionEvents ){
38968 return;
38969 }
38970 piechart.selected = selection;
38971 piechart.highlightChanged([]);
38972 }
38973 },
38974
38975 triggerHighlight : function(highlightedObjects) {
38976 this.parent.triggerHighlight(highlightedObjects);
38977 },
38978
38979 triggerSelection : function(selectedObjects) {
38980 this.parent.triggerSelection(selectedObjects);
38981 },
38982
38983 deselection : function() {
38984 },
38985
38986 filtering : function() {
38987 },
38988
38989 inverseFiltering : function() {
38990 },
38991
38992 triggerRefining : function() {
38993 },
38994
38995 reset : function() {
38996 },
38997
38998 show : function() {
38999 },
39000
39001 hide : function() {
39002 }
39003 };
39004 /*
39005 * FuzzyTimelineRangeSlider.js
39006 *
39007 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
39008 *
39009 * This library is free software; you can redistribute it and/or
39010 * modify it under the terms of the GNU Lesser General Public
39011 * License as published by the Free Software Foundation; either
39012 * version 3 of the License, or (at your option) any later version.
39013 *
39014 * This library is distributed in the hope that it will be useful,
39015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39017 * Lesser General Public License for more details.
39018 *
39019 * You should have received a copy of the GNU Lesser General Public
39020 * License along with this library; if not, write to the Free Software
39021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
39022 * MA 02110-1301 USA
39023 */
39024
39025 /**
39026 * @class FuzzyTimelineRangeSlider
39027 * Implementation for a fuzzy time-ranges slider
39028 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
39029 *
39030 * @param {HTML object} parent div to append the FuzzyTimeline
39031 */
39032 function FuzzyTimelineRangeSlider(parent) {
39033
39034 var rangeSlider = this;
39035
39036 this.parent = parent;
39037 this.options = parent.options;
39038
39039 this.spans;
39040
39041 this.datasets;
39042
39043 this.sliderParentTable = this.parent.gui.sliderTable;
39044 var headerRow = $("<tr></tr>");
39045 var controlsRow = $("<tr></tr>");
39046 $(this.sliderParentTable).append(headerRow).append(controlsRow);
39047
39048 headerRow.append("<td>Time start</td>");
39049 this.rangeStart = document.createElement("select");
39050 controlsRow.append($("<td></td>").append(this.rangeStart));
39051
39052 headerRow.append("<td>Time unit</td>");
39053 this.rangeDropdown = document.createElement("select");
39054 controlsRow.append($("<td></td>").append(this.rangeDropdown));
39055
39056 headerRow.append("<td>Animation</td>");
39057 this.startAnimation = document.createElement("div");
39058 $(this.startAnimation).addClass("smallButton playDisabled");
39059 this.pauseAnimation = document.createElement("div");
39060 $(this.pauseAnimation).addClass("smallButton pauseDisabled");
39061 controlsRow.append($("<td></td>").append(this.startAnimation).append(this.pauseAnimation));
39062
39063 headerRow.append("<td>Dated Objects</td>");
39064 this.numberDatedObjects = 0;
39065 this.numberDatedObjectsDIV = document.createElement("div");
39066 $(this.numberDatedObjectsDIV).addClass("ddbElementsCount");
39067 controlsRow.append($("<td></td>").append(this.numberDatedObjectsDIV));
39068 }
39069
39070 FuzzyTimelineRangeSlider.prototype = {
39071
39072 initialize : function(datasets) {
39073 var rangeSlider = this;
39074 rangeSlider.datasets = datasets;
39075
39076 //reset values
39077 rangeSlider.spans = [];
39078 rangeSlider.spanHash = [];
39079
39080 //find smallest (most accurate) time-span
39081 var smallestSpan;
39082 rangeSlider.numberDatedObjects = 0;
39083 $(this.datasets).each(function(){
39084 $(this.objects).each(function(){
39085 var dataObject = this;
39086 var span;
39087 if (dataObject.isTemporal){
39088 rangeSlider.numberDatedObjects++;
39089 smallestSpan = moment.duration(1,'milliseconds');
39090 } else if (dataObject.isFuzzyTemporal){
39091 rangeSlider.numberDatedObjects++;
39092 span = moment.duration(dataObject.TimeSpanEnd-dataObject.TimeSpanBegin);
39093 if ( (typeof smallestSpan === 'undefined') || (span < smallestSpan))
39094 smallestSpan = span;
39095 }
39096 });
39097 if ((typeof smallestSpan !== 'undefined') && (smallestSpan.asMilliseconds() === 1))
39098 return false;
39099 });
39100
39101 //show number of objects that have a time in header
39102 $(rangeSlider.numberDatedObjectsDIV).empty().append(rangeSlider.numberDatedObjects + " results");
39103
39104 if (typeof smallestSpan === 'undefined')
39105 return;
39106
39107 var fixedSpans = [
39108 moment.duration(1, 'seconds'),
39109 moment.duration(1, 'minutes'),
39110 moment.duration(10, 'minutes'),
39111 moment.duration(15, 'minutes'),
39112 moment.duration(30, 'minutes'),
39113 moment.duration(1, 'hours'),
39114 moment.duration(5, 'hours'),
39115 moment.duration(10, 'hours'),
39116 moment.duration(12, 'hours'),
39117 moment.duration(1, 'days'),
39118 moment.duration(7, 'days'),
39119 moment.duration(1, 'weeks'),
39120 moment.duration(2, 'weeks'),
39121 moment.duration(1, 'months'),
39122 moment.duration(2, 'months'),
39123 moment.duration(3, 'months'),
39124 moment.duration(6, 'months'),
39125 moment.duration(1, 'years'),
39126 moment.duration(5, 'years'),
39127 moment.duration(10, 'years'),
39128 moment.duration(20, 'years'),
39129 moment.duration(25, 'years'),
39130 moment.duration(50, 'years'),
39131 moment.duration(100, 'years'),
39132 moment.duration(200, 'years'),
39133 moment.duration(250, 'years'),
39134 moment.duration(500, 'years'),
39135 moment.duration(1000, 'years'),
39136 moment.duration(2000, 'years'),
39137 moment.duration(2500, 'years'),
39138 moment.duration(5000, 'years'),
39139 moment.duration(10000, 'years'),
39140 ];
39141
39142 //only add spans that are not too small for the data
39143 for (var i = 0; i < fixedSpans.length; i++){
39144 if ( (fixedSpans[i].asMilliseconds() > (smallestSpan.asMilliseconds() * 0.5))
39145 &&
39146 (
39147 rangeSlider.parent.options.showAllPossibleSpans ||
39148 ((rangeSlider.parent.overallMax-rangeSlider.parent.overallMin)/fixedSpans[i]<rangeSlider.options.maxBars)
39149 ))
39150 rangeSlider.spans.push(fixedSpans[i]);
39151 }
39152
39153 $(rangeSlider.rangeDropdown).empty();
39154
39155 $(rangeSlider.rangeDropdown).append("<option>continuous</option>");
39156 var index = 0;
39157 $(rangeSlider.spans).each(function(){
39158 var duration = this;
39159 if (duration < moment.duration(1,'second'))
39160 humanizedSpan = duration.milliseconds() + "ms";
39161 else if (duration < moment.duration(1,'minute'))
39162 humanizedSpan = duration.seconds() + "s";
39163 else if (duration < moment.duration(1,'hour'))
39164 humanizedSpan = duration.minutes() + "min";
39165 else if (duration < moment.duration(1,'day'))
39166 humanizedSpan = duration.hours() + "h";
39167 else if (duration < moment.duration(1,'month'))
39168 humanizedSpan = duration.days() + " days";
39169 else if (duration < moment.duration(1,'year'))
39170 humanizedSpan = duration.months() + " months";
39171 else
39172 humanizedSpan = duration.years() + " years";
39173 $(rangeSlider.rangeDropdown).append("<option index='"+index+"'>"+humanizedSpan+"</option>");
39174 index++;
39175 });
39176
39177 $(rangeSlider.rangeDropdown).change(function( eventObject ){
39178 var handlePosition = $(rangeSlider.rangeDropdown).find("option:selected").first().attr("index");
39179 //if there is no index, "continuous" is selected - so the density plot will be drawn
39180
39181 if (typeof handlePosition === "undefined"){
39182 rangeSlider.parent.switchViewMode("density");
39183 } else {
39184 rangeSlider.parent.switchViewMode("barchart");
39185 }
39186
39187 rangeSlider.parent.slidePositionChanged(rangeSlider.spans[handlePosition]);
39188 });
39189
39190 $(rangeSlider.rangeStart).empty();
39191 //add start of timeline selections
39192 //TODO: add Months/Days/etc., atm there are only years
39193 var starts = [];
39194 var overallMin = rangeSlider.parent.overallMin;
39195 var last = moment(overallMin).year();
39196 starts.push(last);
39197 for (i = 1;;i++){
39198 var date = moment(overallMin).year();
39199 date = date/Math.pow(10,i);
39200 if (Math.abs(date)<1)
39201 break;
39202 date = Math.floor(date);
39203 date = date*Math.pow(10,i);
39204 if (date != last)
39205 starts.push(date);
39206 last = date;
39207 }
39208 $(starts).each(function(){
39209 $(rangeSlider.rangeStart).append("<option>"+this+"</option>");
39210 });
39211
39212 $(rangeSlider.rangeStart).change(function( eventObject ){
39213 var handlePosition = rangeSlider.rangeStart.selectedIndex;
39214 var start = starts[handlePosition];
39215
39216 rangeSlider.parent.overallMin = moment().year(start);
39217 $(rangeSlider.rangeDropdown).change();
39218 });
39219
39220 $(rangeSlider.rangeDropdown).change();
39221
39222 $(rangeSlider.startAnimation).click(function(){
39223 if ($(rangeSlider.startAnimation).hasClass("playEnabled")){
39224 $(rangeSlider.startAnimation).removeClass("playEnabled").addClass("playDisabled");
39225 $(rangeSlider.pauseAnimation).removeClass("pauseDisabled").addClass("pauseEnabled");
39226
39227 rangeSlider.parent.startAnimation();
39228 }
39229 });
39230
39231 $(rangeSlider.pauseAnimation).prop('disabled', true);
39232 $(rangeSlider.pauseAnimation).click(function(){
39233 if ($(rangeSlider.pauseAnimation).hasClass("pauseEnabled")){
39234 $(rangeSlider.startAnimation).removeClass("playDisabled").addClass("playEnabled");
39235 $(rangeSlider.pauseAnimation).removeClass("pauseEnabled").addClass("pauseDisabled");
39236
39237 rangeSlider.parent.pauseAnimation();
39238 }
39239 });
39240 },
39241
39242 triggerHighlight : function(columnElement) {
39243
39244 },
39245
39246 triggerSelection : function(columnElement) {
39247
39248 },
39249
39250 deselection : function() {
39251 },
39252
39253 filtering : function() {
39254 },
39255
39256 inverseFiltering : function() {
39257 },
39258
39259 triggerRefining : function() {
39260 },
39261
39262 reset : function() {
39263 },
39264
39265 show : function() {
39266 },
39267
39268 hide : function() {
39269 }
39270 };
39271 /*
39272 * FuzzyTimelineWidget.js
39273 *
39274 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
39275 *
39276 * This library is free software; you can redistribute it and/or
39277 * modify it under the terms of the GNU Lesser General Public
39278 * License as published by the Free Software Foundation; either
39279 * version 3 of the License, or (at your option) any later version.
39280 *
39281 * This library is distributed in the hope that it will be useful,
39282 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39283 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39284 * Lesser General Public License for more details.
39285 *
39286 * You should have received a copy of the GNU Lesser General Public
39287 * License along with this library; if not, write to the Free Software
39288 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
39289 * MA 02110-1301 USA
39290 */
39291
39292 /**
39293 * @class FuzzyTimelineWidget
39294 * FuzzyTimelineWidget Implementation
39295 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
39296 *
39297 * @param {WidgetWrapper} core wrapper for interaction to other widgets
39298 * @param {HTML object} div parent div to append the FuzzyTimeline widget div
39299 * @param {JSON} options user specified configuration that overwrites options in FuzzyTimelineConfig.js
39300 */
39301 FuzzyTimelineWidget = function(core, div, options) {
39302
39303 this.datasets;
39304 this.selected = undefined;
39305 this.overallMin;
39306 this.overallMax;
39307
39308 this.core = core;
39309 this.core.setWidget(this);
39310
39311 this.options = (new FuzzyTimelineConfig(options)).options;
39312 this.gui = new FuzzyTimelineGui(this, div, this.options);
39313
39314 this.viewMode;
39315 this.density;
39316 this.rangeSlider;
39317 this.rangeBars;
39318 this.rangePiechart;
39319 this.spanHash = [];
39320
39321 this.handles = [];
39322 this.zoomFactor = 1;
39323 }
39324
39325 FuzzyTimelineWidget.prototype = {
39326
39327 initWidget : function(data) {
39328 var fuzzyTimeline = this;
39329
39330 delete fuzzyTimeline.overallMin;
39331 delete fuzzyTimeline.overallMax;
39332
39333 $(fuzzyTimeline.gui.plotDiv).empty();
39334 $(fuzzyTimeline.gui.sliderTable).empty();
39335 delete fuzzyTimeline.rangeSlider;
39336 $(fuzzyTimeline.gui.rangePiechartDiv).empty();
39337 delete fuzzyTimeline.rangePiechart;
39338
39339 fuzzyTimeline.switchViewMode("density");
39340
39341 if ( (data instanceof Array) && (data.length > 0) )
39342 {
39343 fuzzyTimeline.datasets = data;
39344
39345 $(fuzzyTimeline.datasets).each(function(){
39346 $(this.objects).each(function(){
39347 var datemin,datemax;
39348 if (this.isTemporal){
39349 //TODO: allow more than one date
39350 datemin = moment(this.dates[0].date);
39351 datemax = datemin;
39352 } else if (this.isFuzzyTemporal){
39353 //TODO: allow more than one date
39354 datemin = this.TimeSpanBegin;
39355 datemax = this.TimeSpanEnd;
39356 }
39357
39358 if (typeof fuzzyTimeline.overallMin === "undefined")
39359 fuzzyTimeline.overallMin = datemin;
39360 if (typeof fuzzyTimeline.overallMax === "undefined")
39361 fuzzyTimeline.overallMax = datemax;
39362
39363 if (fuzzyTimeline.overallMin > datemin)
39364 fuzzyTimeline.overallMin = datemin;
39365 if (fuzzyTimeline.overallMax < datemax)
39366 fuzzyTimeline.overallMax = datemax;
39367 });
39368 });
39369
39370 fuzzyTimeline.rangeSlider = new FuzzyTimelineRangeSlider(fuzzyTimeline);
39371 fuzzyTimeline.rangeSlider.initialize(fuzzyTimeline.datasets);
39372
39373 fuzzyTimeline.rangePiechart = new FuzzyTimelineRangePiechart(fuzzyTimeline, fuzzyTimeline.gui.rangePiechartDiv);
39374 fuzzyTimeline.rangePiechart.initialize(fuzzyTimeline.datasets);
39375 }
39376 },
39377
39378 switchViewMode : function(viewMode){
39379 var fuzzyTimeline = this;
39380 if (viewMode !== fuzzyTimeline.viewMode){
39381 $(fuzzyTimeline.gui.plotDiv).empty();
39382 if (viewMode === "density"){
39383 fuzzyTimeline.density = new FuzzyTimelineDensity(fuzzyTimeline,fuzzyTimeline.gui.plotDiv);
39384 } else if (viewMode === "barchart"){
39385 fuzzyTimeline.rangeBars = new FuzzyTimelineRangeBars(fuzzyTimeline);
39386 }
39387 fuzzyTimeline.viewMode = viewMode;
39388 }
39389 },
39390
39391 slidePositionChanged : function(spanWidth) {
39392 var fuzzyTimeline = this;
39393 var datasets = fuzzyTimeline.datasets;
39394 if (fuzzyTimeline.viewMode === "density"){
39395 //redraw density plot
39396 fuzzyTimeline.density.drawDensityPlot(datasets);
39397 //select currently selected data (if there is any)
39398 fuzzyTimeline.density.selectionChanged(fuzzyTimeline.selected);
39399 } else if (fuzzyTimeline.viewMode === "barchart"){
39400 //redraw range plot
39401 fuzzyTimeline.rangeBars.drawRangeBarChart(datasets,spanWidth);
39402 //select currently selected data (if there is any)
39403 fuzzyTimeline.rangeBars.selectionChanged(fuzzyTimeline.selected);
39404 }
39405 },
39406
39407 highlightChanged : function(objects) {
39408 var fuzzyTimeline = this;
39409 if( !GeoTemConfig.highlightEvents ){
39410 return;
39411 }
39412 if ( (typeof objects === "undefined") || (objects.length == 0) ){
39413 return;
39414 }
39415 if (fuzzyTimeline.viewMode === "density")
39416 this.density.highlightChanged(objects);
39417 else if (fuzzyTimeline.viewMode === "barchart")
39418 this.rangeBars.highlightChanged(objects);
39419
39420 fuzzyTimeline.rangePiechart.highlightChanged(objects);
39421 },
39422
39423 selectionChanged : function(selection) {
39424 var fuzzyTimeline = this;
39425 if( !GeoTemConfig.selectionEvents ){
39426 return;
39427 }
39428 if (selection.valid())
39429 fuzzyTimeline.selected = selection.objects;
39430 else
39431 delete fuzzyTimeline.selected;
39432 if (fuzzyTimeline.viewMode === "density")
39433 this.density.selectionChanged(fuzzyTimeline.selected);
39434 else if (fuzzyTimeline.viewMode === "barchart")
39435 this.rangeBars.selectionChanged(fuzzyTimeline.selected);
39436
39437 if (selection.valid())
39438 fuzzyTimeline.rangePiechart.selectionChanged(fuzzyTimeline.selected);
39439 else
39440 fuzzyTimeline.rangePiechart.selectionChanged([]);
39441
39442 //selections "overwrite" each other
39443 if (selection.widget != fuzzyTimeline)
39444 fuzzyTimeline.clearHandles();
39445 },
39446
39447 buildSpanArray : function(spanWidth) {
39448 var spanArray = [];
39449 var tickStart = moment(this.overallMin);
39450 do{
39451 spanArray.push(moment(tickStart));
39452 tickStart.add(spanWidth);
39453 } while (tickStart <= this.overallMax);
39454 spanArray.push(moment(tickStart));
39455
39456 this.spanHash.push({spanWidth:spanWidth,overallMin:moment(this.overallMin),spanArray:spanArray});
39457 return(spanArray);
39458 },
39459
39460 getSpanArray : function(spanWidth){
39461 for (var i = 0; i < this.spanHash.length; i++){
39462 var element = this.spanHash[i];
39463 if ( ((this.overallMin-element.overallMin)===0) &&
39464 ((spanWidth-element.spanWidth)===0))
39465 return element.spanArray;
39466 }
39467 return this.buildSpanArray(spanWidth);
39468 },
39469
39470 clearSpanArray : function(){
39471 this.spanHash = [];
39472 },
39473
39474 getTicks : function(dataObject, spanWidth) {
39475 var datemin,datemax;
39476 if (dataObject.isTemporal){
39477 datemin = moment(dataObject.dates[0].date);
39478 datemax = datemin;
39479 } else if (dataObject.isFuzzyTemporal){
39480 datemin = dataObject.TimeSpanBegin;
39481 datemax = dataObject.TimeSpanEnd;
39482 } else{
39483 return;
39484 }
39485
39486 if (typeof spanWidth._data === "undefined"){
39487 //This does only work with millisecond spans, as the length of years is (very) inaccurate.
39488 //(e.g. 100-0 = 99, 2000-1000 = 1001, 5000-0 = 5003, and so on and even more: duration(5000a) = 4932a)
39489 //So the time consuming loop below is needed for accurate dates, when years/months/days etc. are supplied
39490 var firstTick = Math.floor((datemin-this.overallMin)/spanWidth);
39491 var lastTick = Math.floor((datemax-this.overallMin)/spanWidth);
39492 //calculate how much the first (and last) tick and the time-span overlap
39493 var firstTickPercentage = 1;
39494 var lastTickPercentage = 1;
39495 if (firstTick != lastTick){
39496 var secondTickStart = this.overallMin+(firstTick+1)*spanWidth;
39497 var lastTickStart = this.overallMin+lastTick*spanWidth;
39498 firstTickPercentage = (secondTickStart-datemin)/spanWidth;
39499 lastTickPercentage = (datemax-lastTickStart)/spanWidth;
39500 }
39501 if (firstTickPercentage === 0){
39502 firstTick++;
39503 firstTickPercentage = 1;
39504 }
39505 if (lastTickPercentage === 0){
39506 lastTick--;
39507 lastTickPercentage = 1;
39508 }
39509 } else {
39510 var spanArray = this.getSpanArray(spanWidth);
39511 var firstTick, lastTick;
39512 var tickCount = 0;
39513 var tickStart = spanArray[0];
39514 var lastTickStart;
39515 do{
39516 lastTickStart = spanArray[tickCount];
39517 tickCount++;
39518 tickStart = spanArray[tickCount];
39519 if ( (typeof firstTick === "undefined") && (datemin < tickStart) ){
39520 firstTick = tickCount-1;
39521 firstTickPercentage = (tickStart - datemin)/spanWidth;
39522 }
39523 if ( (typeof lastTick === "undefined") && (datemax <= tickStart) ){
39524 lastTick = tickCount-1;
39525 lastTickPercentage = (datemax - lastTickStart)/spanWidth;
39526 }
39527 } while (tickStart < datemax);
39528 if (firstTick == lastTick){
39529 firstTickPercentage = 1;
39530 lastTickPercentage = 1;
39531 }
39532 }
39533
39534 return({ firstTick:firstTick,
39535 lastTick:lastTick,
39536 firstTickPercentage:firstTickPercentage,
39537 lastTickPercentage:lastTickPercentage});
39538 },
39539
39540 getObjects : function(dateStart, dateEnd) {
39541 var fuzzyTimeline = this;
39542 var searchDateStart, searchDateEnd;
39543 if (typeof dateStart !== "undefined")
39544 searchDateStart = moment(dateStart);
39545 if (typeof dateEnd !== "undefined")
39546 searchDateEnd = moment(dateEnd);
39547
39548 var datasets = [];
39549 $(fuzzyTimeline.datasets).each(function(){
39550 var objects = [];
39551 //check if we got "real" datasets, or just array of objects
39552 var datasetObjects = this;
39553 if (typeof this.objects !== "undefined")
39554 datasetObjects = this.objects;
39555 $(datasetObjects).each(function(){
39556 var datemin,datemax;
39557 var dataObject = this;
39558 if (dataObject.isTemporal){
39559 datemin = moment(dataObject.dates[0].date);
39560 datemax = datemin;
39561 } else if (dataObject.isFuzzyTemporal){
39562 datemin = dataObject.TimeSpanBegin;
39563 datemax = dataObject.TimeSpanEnd;
39564 } else{
39565 return;
39566 }
39567
39568 if (typeof searchDateEnd === 'undefined'){
39569 if ( (datemin <= searchDateStart) && (datemax >= searchDateStart) )
39570 objects.push(this);
39571 } else {
39572 if ((datemin < searchDateEnd) && (datemax >= searchDateStart))
39573 objects.push(this);
39574 }
39575 });
39576 datasets.push(objects);
39577 });
39578
39579 return(datasets);
39580 },
39581
39582 triggerHighlight : function(highlightedObjects){
39583 var fuzzyTimeline = this;
39584 if (fuzzyTimeline.viewMode === "density")
39585 fuzzyTimeline.density.highlightChanged(highlightedObjects);
39586 else if (fuzzyTimeline.viewMode === "barchart")
39587 fuzzyTimeline.rangeBars.highlightChanged(highlightedObjects);
39588
39589 fuzzyTimeline.core.triggerHighlight(highlightedObjects);
39590 },
39591
39592 triggerSelection : function(selectedObjects){
39593 var fuzzyTimeline = this;
39594 fuzzyTimeline.selected = selectedObjects;
39595 if (fuzzyTimeline.viewMode === "density")
39596 fuzzyTimeline.density.selectionChanged(selectedObjects);
39597 else if (fuzzyTimeline.viewMode === "barchart")
39598 fuzzyTimeline.rangeBars.selectionChanged(selectedObjects);
39599
39600 selection = new Selection(selectedObjects);
39601
39602 fuzzyTimeline.core.triggerSelection(selection);
39603 },
39604
39605 addHandle : function(x1,x2){
39606 var fuzzyTimeline = this;
39607 //make sure the interval is ordered correctly
39608 if (x2<x1){
39609 var temp = x1;
39610 x1 = x2;
39611 x2 = temp;
39612 }
39613 fuzzyTimeline.handles.push({x1:x1,x2:x2});
39614 fuzzyTimeline.drawHandles();
39615 //enabled "play" button
39616 $(fuzzyTimeline.rangeSlider.startAnimation).removeClass("playDisabled").addClass("playEnabled");
39617 },
39618
39619 selectByX : function(x1,x2){
39620 var fuzzyTimeline = this;
39621 if (fuzzyTimeline.viewMode === "density"){
39622 fuzzyTimeline.density.selectByX(x1,x2);
39623 } else if (fuzzyTimeline.viewMode === "barchart"){
39624 fuzzyTimeline.rangeBars.selectByX(x1,x2);
39625 }
39626 },
39627
39628 drawHandles : function(){
39629 var fuzzyTimeline = this;
39630
39631 $(fuzzyTimeline.gui.plotDiv).find(".plotHandle").remove();
39632 $(fuzzyTimeline.gui.plotDiv).find(".dragTimeRangeAlt").remove();
39633 $(fuzzyTimeline.gui.plotDiv).find(".plotHandleBox").remove();
39634
39635 var plotHeight = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).height();
39636 var plotWidth = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).width();
39637 //flot sends the wrong width if we extend the parent div, so scale it accordingly
39638 plotWidth = plotWidth*fuzzyTimeline.zoomFactor;
39639 var plotOffset = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).getPlotOffset().left;
39640
39641 $(fuzzyTimeline.handles).each(function(){
39642 var handle = this;
39643
39644 var moveLeftHandle = function(){
39645 leftHandle.style.left = handle.x1-$(leftHandle).width() + "px";
39646 };
39647
39648 var moveRightHandle = function(){
39649 rightHandle.style.left = handle.x2+ "px";
39650 };
39651
39652 var resizeHandleBox = function(){
39653 handleBox.style.left = handle.x1+"px";
39654 $(handleBox).width(handle.x2-handle.x1);
39655 };
39656
39657 var moveDragButton = function(){
39658 dragButton.style.left = (handle.x1+handle.x2)/2 - $(dragButton).width()/2 + "px";
39659 };
39660
39661 var leftHandle = document.createElement("div");
39662 leftHandle.title = GeoTemConfig.getString('leftHandle');
39663 leftHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "leftHandle.png" + ")";
39664 leftHandle.setAttribute('class', 'plotHandle plotHandleIcon');
39665 leftHandle.style.visibility = "visible";
39666 $(fuzzyTimeline.gui.plotDiv).append(leftHandle);
39667 moveLeftHandle();
39668 leftHandle.style.top = plotHeight/2-$(leftHandle).height()/2 + "px";
39669
39670 var rightHandle = document.createElement("div");
39671 rightHandle.title = GeoTemConfig.getString('leftHandle');
39672 rightHandle.style.backgroundImage = "url(" + GeoTemConfig.path + "rightHandle.png" + ")";
39673 rightHandle.setAttribute('class', 'plotHandle plotHandleIcon');
39674 rightHandle.style.visibility = "visible";
39675 moveRightHandle();
39676 $(fuzzyTimeline.gui.plotDiv).append(rightHandle);
39677
39678 rightHandle.style.top = plotHeight/2-$(rightHandle).height()/2 + "px";
39679
39680 var handleBox = document.createElement("div");
39681 $(fuzzyTimeline.gui.plotDiv).append(handleBox);
39682 $(handleBox).addClass("plotHandleBox");
39683 resizeHandleBox();
39684 $(handleBox).height(plotHeight);
39685
39686 var dragButton = document.createElement("div");
39687 dragButton.title = GeoTemConfig.getString('dragTimeRange');
39688 dragButton.style.backgroundImage = "url(" + GeoTemConfig.path + "drag.png" + ")";
39689 dragButton.setAttribute('class', 'dragTimeRangeAlt plotHandleIcon');
39690 $(fuzzyTimeline.gui.plotDiv).append(dragButton);
39691 moveDragButton();
39692 dragButton.style.top = plotHeight + "px";
39693
39694 $(leftHandle).mousedown(function(){
39695 $(fuzzyTimeline.gui.plotDiv).mousemove(function(eventObj){
39696 var x = eventObj.clientX;
39697 x += $(fuzzyTimeline.gui.plotDiv).parent().scrollLeft();
39698 if ((x < handle.x2) &&
39699 (x >= plotOffset)){
39700 x = x - leftHandle.offsetWidth;
39701 handle.x1 = x + $(leftHandle).width();
39702
39703 moveLeftHandle();
39704 resizeHandleBox();
39705 moveDragButton();
39706 }
39707 });
39708 $(fuzzyTimeline.gui.plotDiv).mouseup(function(eventObj){
39709 fuzzyTimeline.selectByX(handle.x1,handle.x2);
39710 $(fuzzyTimeline.gui.plotDiv).unbind("mouseup");
39711 $(fuzzyTimeline.gui.plotDiv).unbind("mousemove");
39712 });
39713 });
39714
39715 $(rightHandle).mousedown(function(){
39716 $(fuzzyTimeline.gui.plotDiv).mousemove(function(eventObj){
39717 var x = eventObj.clientX;
39718 x += $(fuzzyTimeline.gui.plotDiv).parent().scrollLeft();
39719 x = x - rightHandle.offsetWidth;
39720 if ((x > handle.x1) &&
39721 (x <= plotOffset+plotWidth)){
39722 handle.x2 = x;
39723
39724 moveRightHandle();
39725 resizeHandleBox();
39726 moveDragButton();
39727 }
39728 });
39729 $(fuzzyTimeline.gui.plotDiv).mouseup(function(eventObj){
39730 fuzzyTimeline.selectByX(handle.x1,handle.x2);
39731 $(fuzzyTimeline.gui.plotDiv).unbind("mouseup");
39732 $(fuzzyTimeline.gui.plotDiv).unbind("mousemove");
39733 });
39734 });
39735
39736 $(dragButton).mousedown(function(){
39737 $(fuzzyTimeline.gui.plotDiv).mousemove(function(eventObj){
39738 var x = eventObj.clientX;
39739 //TODO: for some reason we don't need the scoll offset here
39740 //this should be investigated?
39741 //x += $(fuzzyTimeline.gui.plotDiv).parent().scrollLeft();
39742 var xdiff = x - $(dragButton).offset().left - $(dragButton).width()/2;
39743 handle.x1 = handle.x1+xdiff;
39744 handle.x2 = handle.x2+xdiff;
39745
39746 moveLeftHandle();
39747 moveRightHandle();
39748 resizeHandleBox();
39749 moveDragButton();
39750 });
39751 $(fuzzyTimeline.gui.plotDiv).mouseup(function(eventObj){
39752 if (handle.x1 < plotOffset)
39753 handle.x1 = plotOffset;
39754 if (handle.x2 > plotOffset+plotWidth)
39755 handle.x2 = plotOffset+plotWidth;
39756
39757 moveLeftHandle();
39758 moveRightHandle();
39759 resizeHandleBox();
39760 moveDragButton();
39761
39762 fuzzyTimeline.selectByX(handle.x1,handle.x2);
39763 $(fuzzyTimeline.gui.plotDiv).unbind("mouseup");
39764 $(fuzzyTimeline.gui.plotDiv).unbind("mousemove");
39765 });
39766 });
39767 });
39768 },
39769
39770 clearHandles : function(){
39771 var fuzzyTimeline = this;
39772 $(fuzzyTimeline.gui.plotDiv).find(".plotHandle").remove();
39773 $(fuzzyTimeline.gui.plotDiv).find(".dragTimeRangeAlt").remove();
39774 $(fuzzyTimeline.gui.plotDiv).find(".plotHandleBox").remove();
39775 fuzzyTimeline.handles = [];
39776 //disable buttons
39777 $(fuzzyTimeline.rangeSlider.startAnimation).removeClass("playEnabled").addClass("playDisabled");
39778 $(fuzzyTimeline.rangeSlider.pauseAnimation).removeClass("pauseEnabled").addClass("pauseDisabled");
39779 //stop the animation (if one was running)
39780 fuzzyTimeline.pauseAnimation();
39781 },
39782
39783 startAnimation : function(){
39784 var fuzzyTimeline = this;
39785 fuzzyTimeline.loopFunction = function(steps){
39786 $(fuzzyTimeline.handles).each(function(){
39787 if (typeof steps === "undefined")
39788 steps = 1;
39789
39790 var handle = this;
39791 var x1 = handle.x1;
39792 var x2 = handle.x2;
39793
39794 if (typeof handle.width === "undefined")
39795 handle.width = x2-x1;
39796
39797 var plotWidth = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).width();
39798 var plotOffset = (fuzzyTimeline.density.plot?fuzzyTimeline.density.plot:fuzzyTimeline.rangeBars.plot).getPlotOffset().left;
39799
39800 var plotMax = plotWidth+plotOffset;
39801
39802 //TODO: has to be plotMin
39803 if (!((x1 === plotOffset)&&(x2-x1 <= handle.width))){
39804 x1 += steps;
39805 }
39806 if (x2 <= plotMax){
39807 x2 += steps;
39808 if (x2 > plotMax)
39809 x2 = plotMax;
39810 if (x2-x1 > handle.width){
39811 x1 = x2-handle.width;
39812 }
39813 }
39814 if (x1 >= plotMax){
39815 //TODO: has to be plotMin
39816 x1 = plotOffset;
39817 x2 = plotOffset;
39818 }
39819
39820 handle.x1 = x1;
39821 handle.x2 = x2;
39822
39823 fuzzyTimeline.drawHandles();
39824 fuzzyTimeline.selectByX(handle.x1, handle.x2);
39825 });
39826 };
39827
39828 fuzzyTimeline.loopId = setInterval(function(){
39829 fuzzyTimeline.loopFunction(10);
39830 }, 100);
39831 },
39832
39833 pauseAnimation : function(){
39834 var fuzzyTimeline = this;
39835 clearInterval(fuzzyTimeline.loopId);
39836 $(fuzzyTimeline.handles).each(function(){
39837 var handle = this;
39838 delete handle.width;
39839 });
39840 },
39841
39842 //This function enlargens the plot area
39843 zoomPlot : function(zoomFactor){
39844 var fuzzyTimeline = this;
39845 var oldZoomFactor = fuzzyTimeline.zoomFactor;
39846 fuzzyTimeline.zoomFactor = zoomFactor;
39847 if (zoomFactor > 1){
39848 $(fuzzyTimeline.gui.plotDiv).width(zoomFactor*100+"%");
39849 //leave place for the scrollbar
39850 $(fuzzyTimeline.gui.plotDiv).height(fuzzyTimeline.gui.plotDIVHeight-20);
39851 } else{
39852 $(fuzzyTimeline.gui.plotDiv).width("100%");
39853 $(fuzzyTimeline.gui.plotDiv).height(fuzzyTimeline.gui.plotDIVHeight);
39854 }
39855
39856 //fit handles
39857 //this does not make much sense, as the selections are _completely_ different
39858 //for each scale rate, as the objects may reside in different "ticks" of the graph
39859 $(fuzzyTimeline.handles).each(function(){
39860 var handle = this;
39861 handle.x1 = handle.x1 * (zoomFactor/oldZoomFactor);
39862 handle.x2 = handle.x2 * (zoomFactor/oldZoomFactor);
39863 });
39864 }
39865 };
39866 /*
39867 * Overlayloader.js
39868 *
39869 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
39870 *
39871 * This library is free software; you can redistribute it and/or
39872 * modify it under the terms of the GNU Lesser General Public
39873 * License as published by the Free Software Foundation; either
39874 * version 3 of the License, or (at your option) any later version.
39875 *
39876 * This library is distributed in the hope that it will be useful,
39877 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39878 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39879 * Lesser General Public License for more details.
39880 *
39881 * You should have received a copy of the GNU Lesser General Public
39882 * License along with this library; if not, write to the Free Software
39883 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
39884 * MA 02110-1301 USA
39885 */
39886
39887 /**
39888 * @class Overlayloader
39889 * Implementation for a Overlayloader UI
39890 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
39891 *
39892 * @param {HTML object} parent div to append the Overlayloader
39893 */
39894 function Overlayloader(parent) {
39895
39896 this.overlayLoader = this;
39897
39898 this.parent = parent;
39899 this.options = parent.options;
39900 this.attachedMapWidgets = parent.attachedMapWidgets;
39901
39902 this.overlays = [];
39903
39904 this.initialize();
39905 }
39906
39907 Overlayloader.prototype = {
39908
39909 show : function() {
39910 this.overlayloaderDiv.style.display = "block";
39911 },
39912
39913 hide : function() {
39914 this.overlayloaderDiv.style.display = "none";
39915 },
39916
39917 initialize : function() {
39918
39919 this.addKMLLoader();
39920 this.addKMZLoader();
39921 this.addArcGISWMSLoader();
39922 this.addXYZLoader();
39923 this.addRomanEmpireLoader();
39924 this.addConfigLoader();
39925
39926 // trigger change event on the select so
39927 // that only the first loader div will be shown
39928 $(this.parent.gui.loaderTypeSelect).change();
39929 },
39930
39931 distributeKML : function(kmlURL) {
39932 var newOverlay = new Object();
39933 newOverlay.name = kmlURL;
39934 newOverlay.layers = [];
39935
39936 $(this.attachedMapWidgets).each(function(){
39937 var newLayer = new OpenLayers.Layer.Vector("KML", {
39938 projection: this.openlayersMap.displayProjection,
39939 strategies: [new OpenLayers.Strategy.Fixed()],
39940 protocol: new OpenLayers.Protocol.HTTP({
39941 url: kmlURL,
39942 format: new OpenLayers.Format.KML({
39943 extractStyles: true,
39944 extractAttributes: true
39945 })
39946 })
39947 });
39948
39949 newOverlay.layers.push({map:this.openlayersMap,layer:newLayer});
39950
39951 this.openlayersMap.addLayer(newLayer);
39952 });
39953
39954 this.overlays.push(newOverlay);
39955 this.parent.gui.refreshOverlayList();
39956 },
39957
39958 distributeKMZ : function(kmzURL) {
39959 var newOverlay = new Object();
39960 newOverlay.name = kmzURL;
39961 newOverlay.layers = [];
39962
39963 $(this.attachedMapWidgets).each(function(){
39964 var newLayer = new OpenLayers.Layer.Vector("KML", {
39965 projection: this.openlayersMap.displayProjection,
39966 strategies: [new OpenLayers.Strategy.Fixed()],
39967 format: OpenLayers.Format.KML,
39968 extractAttributes: true
39969 });
39970
39971 newOverlay.layers.push({map:this.openlayersMap,layer:newLayer});
39972
39973 var map = this.openlayersMap;
39974
39975 GeoTemConfig.getKmz(kmzURL, function(kmlDoms){
39976 $(kmlDoms).each(function(){
39977 var kml = new OpenLayers.Format.KML().read(this);
39978 newLayer.addFeatures(kml);
39979 map.addLayer(newLayer);
39980 });
39981 });
39982 });
39983
39984 this.overlays.push(newOverlay);
39985 this.parent.gui.refreshOverlayList();
39986 },
39987
39988 distributeArcGISWMS : function(wmsURL, wmsLayer) {
39989 var newOverlay = new Object();
39990 newOverlay.name = wmsURL + " - " + wmsLayer;
39991 newOverlay.layers = [];
39992
39993 var newLayer = new OpenLayers.Layer.WMS("ArcGIS WMS label", wmsURL, {
39994 layers: wmsLayer,
39995 format: "image/png",
39996 transparent: "true"
39997 }
39998 ,{
39999 displayOutsideMaxExtent: true,
40000 isBaseLayer: false,
40001 projection : "EPSG:3857"
40002 }
40003 );
40004
40005 newLayer.setIsBaseLayer(false);
40006 $(this.attachedMapWidgets).each(function(){
40007 this.openlayersMap.addLayer(newLayer);
40008 newOverlay.layers.push({map:this.openlayersMap,layer:newLayer});
40009 });
40010
40011 this.overlays.push(newOverlay);
40012 this.parent.gui.refreshOverlayList();
40013 },
40014
40015 distributeXYZ : function(xyzURL) {
40016 var newOverlay = new Object();
40017 newOverlay.name = xyzURL;
40018 newOverlay.layers = [];
40019
40020 var newLayer = new OpenLayers.Layer.XYZ(
40021 "XYZ Layer",
40022 [
40023 xyzURL
40024 ], {
40025 sphericalMercator: true,
40026 transitionEffect: "resize",
40027 buffer: 1,
40028 numZoomLevels: 12,
40029 transparent : true
40030 }
40031 );
40032
40033 newLayer.setIsBaseLayer(false);
40034 $(this.attachedMapWidgets).each(function(){
40035 this.openlayersMap.addLayer(newLayer);
40036 this.openlayersMap.setBaseLayer(newLayer);
40037 newOverlay.layers.push({map:this.openlayersMap,layer:newLayer});
40038 });
40039
40040 this.overlays.push(newOverlay);
40041 this.parent.gui.refreshOverlayList();
40042 },
40043
40044 addKMLLoader : function() {
40045 $(this.parent.gui.loaderTypeSelect).append("<option value='KMLLoader'>KML File URL</option>");
40046
40047 this.KMLLoaderTab = document.createElement("div");
40048 $(this.KMLLoaderTab).attr("id","KMLLoader");
40049
40050 this.kmlURL = document.createElement("input");
40051 $(this.kmlURL).attr("type","text");
40052 $(this.KMLLoaderTab).append(this.kmlURL);
40053
40054 this.loadKMLButton = document.createElement("button");
40055 $(this.loadKMLButton).text("load KML");
40056 $(this.KMLLoaderTab).append(this.loadKMLButton);
40057
40058 $(this.loadKMLButton).click($.proxy(function(){
40059 var kmlURL = $(this.kmlURL).val();
40060 if (kmlURL.length == 0)
40061 return;
40062 if (typeof this.options.proxy != 'undefined')
40063 kmlURL = this.options.proxy + kmlURL;
40064
40065 this.distributeKML(kmlURL);
40066 },this));
40067
40068 $(this.parent.gui.loaders).append(this.KMLLoaderTab);
40069 },
40070
40071 addKMZLoader : function() {
40072 $(this.parent.gui.loaderTypeSelect).append("<option value='KMZLoader'>KMZ File URL</option>");
40073
40074 this.KMZLoaderTab = document.createElement("div");
40075 $(this.KMZLoaderTab).attr("id","KMZLoader");
40076
40077 this.kmzURL = document.createElement("input");
40078 $(this.kmzURL).attr("type","text");
40079 $(this.KMZLoaderTab).append(this.kmzURL);
40080
40081 this.loadKMZButton = document.createElement("button");
40082 $(this.loadKMZButton).text("load KMZ");
40083 $(this.KMZLoaderTab).append(this.loadKMZButton);
40084
40085 $(this.loadKMZButton).click($.proxy(function(){
40086 var kmzURL = $(this.kmzURL).val();
40087 if (kmzURL.length == 0)
40088 return;
40089 if (typeof this.options.proxy != 'undefined')
40090 kmzURL = this.options.proxy + kmzURL;
40091
40092 this.distributeKMZ(kmzURL);
40093 },this));
40094
40095 $(this.parent.gui.loaders).append(this.KMZLoaderTab);
40096 },
40097
40098 addArcGISWMSLoader : function() {
40099 $(this.parent.gui.loaderTypeSelect).append("<option value='ArcGISWMSLoader'>ArcGIS WMS</option>");
40100
40101 this.ArcGISWMSLoaderTab = document.createElement("div");
40102 $(this.ArcGISWMSLoaderTab).attr("id","ArcGISWMSLoader");
40103
40104 $(this.ArcGISWMSLoaderTab).append("URL: ");
40105
40106 this.wmsURL = document.createElement("input");
40107 $(this.wmsURL).attr("type","text");
40108 $(this.ArcGISWMSLoaderTab).append(this.wmsURL);
40109
40110 $(this.ArcGISWMSLoaderTab).append("Layer: ");
40111
40112 this.wmsLayer = document.createElement("input");
40113 $(this.wmsLayer).attr("type","text");
40114 $(this.ArcGISWMSLoaderTab).append(this.wmsLayer);
40115
40116 this.loadArcGISWMSButton = document.createElement("button");
40117 $(this.loadArcGISWMSButton).text("load Layer");
40118 $(this.ArcGISWMSLoaderTab).append(this.loadArcGISWMSButton);
40119
40120 $(this.loadArcGISWMSButton).click($.proxy(function(){
40121 var wmsURL = $(this.wmsURL).val();
40122 var wmsLayer = $(this.wmsLayer).val();
40123 if (wmsURL.length == 0)
40124 return;
40125
40126 this.distributeArcGISWMS(wmsURL, wmsLayer);
40127 },this));
40128
40129 $(this.parent.gui.loaders).append(this.ArcGISWMSLoaderTab);
40130 },
40131
40132 addXYZLoader : function() {
40133 $(this.parent.gui.loaderTypeSelect).append("<option value='XYZLoader'>XYZ Layer</option>");
40134
40135 this.XYZLoaderTab = document.createElement("div");
40136 $(this.XYZLoaderTab).attr("id","XYZLoader");
40137
40138 $(this.XYZLoaderTab).append("URL (with x,y,z variables): ");
40139
40140 this.xyzURL = document.createElement("input");
40141 $(this.xyzURL).attr("type","text");
40142 $(this.XYZLoaderTab).append(this.xyzURL);
40143
40144 this.loadXYZButton = document.createElement("button");
40145 $(this.loadXYZButton).text("load Layer");
40146 $(this.XYZLoaderTab).append(this.loadXYZButton);
40147
40148 $(this.loadXYZButton).click($.proxy(function(){
40149 var xyzURL = $(this.xyzURL).val();
40150 if (xyzURL.length == 0)
40151 return;
40152
40153 this.distributeXYZ(xyzURL);
40154 },this));
40155
40156 $(this.parent.gui.loaders).append(this.XYZLoaderTab);
40157 },
40158
40159 addRomanEmpireLoader : function() {
40160 $(this.parent.gui.loaderTypeSelect).append("<option value='RomanEmpireLoader'>Roman Empire</option>");
40161
40162 this.RomanEmpireLoaderTab = document.createElement("div");
40163 $(this.RomanEmpireLoaderTab).attr("id","RomanEmpireLoader");
40164
40165 this.loadRomanEmpireButton = document.createElement("button");
40166 $(this.loadRomanEmpireButton).text("load Layer");
40167 $(this.RomanEmpireLoaderTab).append(this.loadRomanEmpireButton);
40168
40169 $(this.loadRomanEmpireButton).click($.proxy(function(){
40170 this.distributeXYZ("http://pelagios.dme.ait.ac.at/tilesets/imperium/${z}/${x}/${y}.png");
40171 },this));
40172
40173 $(this.parent.gui.loaders).append(this.RomanEmpireLoaderTab);
40174 },
40175
40176 addConfigLoader : function() {
40177 if ( (this.parent.options.wms_overlays instanceof Array) &&
40178 (this.parent.options.wms_overlays.length > 0) ){
40179 var overlayloader = this;
40180
40181 $(this.parent.gui.loaderTypeSelect).append("<option value='ConfigLoader'>Other WMS maps</option>");
40182
40183 this.ConfigLoaderTab = document.createElement("div");
40184 $(this.ConfigLoaderTab).attr("id","ConfigLoader");
40185
40186 this.ConfigMapSelect = document.createElement("select");
40187 $(this.parent.options.wms_overlays).each(function(){
40188 var name = this.name, server = this.server, layer = this.layer;
40189 $(overlayloader.ConfigMapSelect).append("<option layer='"+layer+"' server='"+server+"' >"+name+"</option>");
40190 });
40191
40192 $(this.ConfigLoaderTab).append(this.ConfigMapSelect);
40193
40194 this.loadConfigMapButton = document.createElement("button");
40195 $(this.loadConfigMapButton).text("load Layer");
40196 $(this.ConfigLoaderTab).append(this.loadConfigMapButton);
40197
40198 $(this.loadConfigMapButton).click($.proxy(function(){
40199 var server = $(this.ConfigMapSelect).find(":selected").attr("server");
40200 var layer = $(this.ConfigMapSelect).find(":selected").attr("layer");
40201 this.distributeArcGISWMS(server,layer);
40202 },this));
40203
40204 $(this.parent.gui.loaders).append(this.ConfigLoaderTab);
40205 }
40206 }
40207
40208 };
40209 /*
40210 * OverlayloaderConfig.js
40211 *
40212 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
40213 *
40214 * This library is free software; you can redistribute it and/or
40215 * modify it under the terms of the GNU Lesser General Public
40216 * License as published by the Free Software Foundation; either
40217 * version 3 of the License, or (at your option) any later version.
40218 *
40219 * This library is distributed in the hope that it will be useful,
40220 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40221 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40222 * Lesser General Public License for more details.
40223 *
40224 * You should have received a copy of the GNU Lesser General Public
40225 * License along with this library; if not, write to the Free Software
40226 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
40227 * MA 02110-1301 USA
40228 */
40229
40230 /**
40231 * @class OverlayloaderConfig
40232 * Overlayloader Configuration File
40233 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
40234 */
40235 function OverlayloaderConfig(options) {
40236
40237 this.options = {
40238 wms_overlays : [
40239 //e.g. {name:'name', server:'url', layer:'layer'},
40240 ],
40241 proxy : 'php/proxy.php?address='
40242 };
40243 if ( typeof options != 'undefined') {
40244 $.extend(this.options, options);
40245 }
40246
40247 };
40248 /*
40249 * OverlayloaderGui.js
40250 *
40251 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
40252 *
40253 * This library is free software; you can redistribute it and/or
40254 * modify it under the terms of the GNU Lesser General Public
40255 * License as published by the Free Software Foundation; either
40256 * version 3 of the License, or (at your option) any later version.
40257 *
40258 * This library is distributed in the hope that it will be useful,
40259 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40260 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40261 * Lesser General Public License for more details.
40262 *
40263 * You should have received a copy of the GNU Lesser General Public
40264 * License along with this library; if not, write to the Free Software
40265 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
40266 * MA 02110-1301 USA
40267 */
40268
40269 /**
40270 * @class OverlayloaderGui
40271 * Overlayloader GUI Implementation
40272 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
40273 *
40274 * @param {OverlayloaderWidget} parent Overlayloader widget object
40275 * @param {HTML object} div parent div to append the Overlayloader gui
40276 * @param {JSON} options Overlayloader configuration
40277 */
40278 function OverlayloaderGui(overlayloader, div, options) {
40279
40280 this.parent = overlayloader;
40281 var overlayloaderGui = this;
40282
40283 this.overlayloaderContainer = div;
40284 this.overlayloaderContainer.style.position = 'relative';
40285
40286 this.loaderTypeSelect = document.createElement("select");
40287 div.appendChild(this.loaderTypeSelect);
40288
40289 this.loaders = document.createElement("div");
40290 div.appendChild(this.loaders);
40291
40292 this.overlayList = document.createElement("div");
40293 div.appendChild(this.overlayList);
40294
40295 $(this.loaderTypeSelect).change(function(){
40296 var activeLoader = $(this).val();
40297 $(overlayloaderGui.loaders).find("div").each(function(){
40298 if ($(this).attr("id") == activeLoader)
40299 $(this).show();
40300 else
40301 $(this).hide();
40302 });
40303 });
40304
40305 this.refreshOverlayList = function(){
40306 var overlayloaderGui = this;
40307
40308 $(overlayloaderGui.overlayList).empty();
40309 $(this.parent.overlayLoader.overlays).each(function(){
40310 var overlay = this;
40311 $(overlayloaderGui.overlayList).append(overlay.name);
40312 var link = document.createElement("a");
40313 $(link).text("(x)");
40314 link.href="";
40315
40316 $(link).click($.proxy(function(){
40317 $(overlay.layers).each(function(){
40318 this.map.removeLayer(this.layer);
40319 });
40320
40321 var overlays = overlayloaderGui.parent.overlayLoader.overlays;
40322
40323 overlays = $.grep(overlays, function(value) {
40324 return overlay != value;
40325 });
40326
40327 overlayloaderGui.parent.overlayLoader.overlays = overlays;
40328
40329 overlayloaderGui.refreshOverlayList();
40330
40331 return(false);
40332 },{overlay:overlay,overlayloaderGui:overlayloaderGui}));
40333 $(overlayloaderGui.overlayList).append(link);
40334 });
40335 };
40336 };
40337 /*
40338 * OverlayloaderWidget.js
40339 *
40340 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
40341 *
40342 * This library is free software; you can redistribute it and/or
40343 * modify it under the terms of the GNU Lesser General Public
40344 * License as published by the Free Software Foundation; either
40345 * version 3 of the License, or (at your option) any later version.
40346 *
40347 * This library is distributed in the hope that it will be useful,
40348 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40349 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40350 * Lesser General Public License for more details.
40351 *
40352 * You should have received a copy of the GNU Lesser General Public
40353 * License along with this library; if not, write to the Free Software
40354 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
40355 * MA 02110-1301 USA
40356 */
40357
40358 /**
40359 * @class OverlayloaderWidget
40360 * OverlayloaderWidget Implementation
40361 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
40362 *
40363 * @param {WidgetWrapper} core wrapper for interaction to other widgets
40364 * @param {HTML object} div parent div to append the Overlayloader widget div
40365 * @param {JSON} options user specified configuration that overwrites options in OverlayloaderConfig.js
40366 */
40367 OverlayloaderWidget = function(core, div, options) {
40368
40369 this.core = core;
40370 this.core.setWidget(this);
40371
40372 this.options = (new OverlayloaderConfig(options)).options;
40373 this.gui = new OverlayloaderGui(this, div, this.options);
40374
40375 this.attachedMapWidgets = new Array();
40376
40377 this.overlayLoader = new Overlayloader(this);
40378 }
40379
40380 OverlayloaderWidget.prototype = {
40381
40382 initWidget : function() {
40383
40384 var overlayloaderWidget = this;
40385 },
40386
40387 highlightChanged : function(objects) {
40388 if( !GeoTemConfig.highlightEvents ){
40389 return;
40390 }
40391 },
40392
40393 selectionChanged : function(selection) {
40394 if( !GeoTemConfig.selectionEvents ){
40395 return;
40396 }
40397 },
40398
40399 triggerHighlight : function(item) {
40400 },
40401
40402 tableSelection : function() {
40403 },
40404
40405 deselection : function() {
40406 },
40407
40408 filtering : function() {
40409 },
40410
40411 inverseFiltering : function() {
40412 },
40413
40414 triggerRefining : function() {
40415 },
40416
40417 reset : function() {
40418 },
40419
40420 attachMapWidget : function(widget) {
40421 this.attachedMapWidgets.push(widget);
40422 }
40423 };
40424 /*
40425 * PieChart.js
40426 *
40427 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
40428 *
40429 * This library is free software; you can redistribute it and/or
40430 * modify it under the terms of the GNU Lesser General Public
40431 * License as published by the Free Software Foundation; either
40432 * version 3 of the License, or (at your option) any later version.
40433 *
40434 * This library is distributed in the hope that it will be useful,
40435 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40436 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40437 * Lesser General Public License for more details.
40438 *
40439 * You should have received a copy of the GNU Lesser General Public
40440 * License along with this library; if not, write to the Free Software
40441 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
40442 * MA 02110-1301 USA
40443 */
40444
40445 /**
40446 * @class PieChart
40447 * Implementation for a PieChart
40448 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
40449 *
40450 * @param {HTML object} parent div to append the PieChart
40451 */
40452 function PieChart(parent, watchedDataset, watchedColumn, selectionFunction) {
40453
40454 if ((typeof selectionFunction !== "undefined") &&
40455 (typeof selectionFunction.type !== "undefined") &&
40456 (typeof selectionFunction.categories !== "undefined")){
40457 this.type = selectionFunction.type;
40458 this.categories = selectionFunction.categories;
40459 }
40460 this.pieChart = this;
40461 this.pieChartDiv;
40462 this.preHighlightObjects;
40463 this.highlightedLabel;
40464
40465 this.informationDIV;
40466 this.pieChartLabel;
40467
40468 this.parent = parent;
40469 this.options = parent.options;
40470
40471 this.watchedDatasetObject;
40472 this.watchedDataset = parseInt(watchedDataset);
40473 this.watchColumn = watchedColumn;
40474 if (typeof selectionFunction !== "undefined")
40475 this.selectionFunction = selectionFunction;
40476 else
40477 //default selectionFunction returns value (creates "distinct" piechart)
40478 this.selectionFunction = function(columnData){return columnData;};
40479 }
40480
40481 PieChart.prototype = {
40482
40483 remove : function() {
40484 for (var i = 0; i < this.parent.pieCharts.length; i++){
40485 if (this.parent.pieCharts[i] === this)
40486 this.parent.pieCharts[i] = null;
40487 }
40488 $(this.pieChartDiv).remove();
40489 $(this.informationDIV).remove();
40490 this.parent.redrawPieCharts();
40491 },
40492
40493 refreshLabel : function(){
40494 $(this.pieChartLabel).empty();
40495 $(this.pieChartLabel).append(this.watchedDatasetObject.label + " - " + this.watchColumn);
40496
40497 var c = GeoTemConfig.getColor(this.watchedDataset);
40498 $(this.pieChartLabel).css("color","rgb("+c.r1+","+c.g1+","+c.b1+")");
40499 },
40500
40501 initialize : function() {
40502 var pieChart = this;
40503
40504 if (typeof this.pieChartDiv === "undefined"){
40505 this.informationDIV = document.createElement("div");
40506 this.pieChartLabel = $("<span></span>");
40507 $(this.informationDIV).append(this.pieChartLabel);
40508 this.refreshLabel();
40509
40510 var removeButton = document.createElement("button");
40511 $(this.informationDIV).append(removeButton);
40512 $(removeButton).text("remove");
40513 $(removeButton).click(function(){
40514 pieChart.remove();
40515 });
40516
40517 //only allow editing if it is a "manually" created piechart
40518 //automatic (with a selection function) ones, can lead to numerous problems,
40519 //e.g. too many categories or numeral categories threated as text ones
40520 if ((typeof pieChart.type !== "undefined")&&
40521 (typeof pieChart.categories !== "undefined")){
40522 var editButton = document.createElement("button");
40523 $(this.informationDIV).append(editButton);
40524 $(editButton).text("edit");
40525 $(editButton).click(function(){
40526 var chooser = new PieChartCategoryChooser(
40527 pieChart.parent,
40528 pieChart.parent.options,
40529 pieChart.watchedDataset,
40530 pieChart.watchColumn,
40531 pieChart.type,
40532 pieChart.categories);
40533 });
40534
40535 //add save button
40536 if (pieChart.options.allowLocalStorage){
40537 var saveButton = document.createElement("button");
40538 $(this.informationDIV).append(saveButton);
40539 $(saveButton).text("save");
40540 $(saveButton).click(function(){
40541 $( "<div>" +
40542 "pie chart name : " +
40543 "<input type='text' size=30 id='saveName' class='ui-widget-content ui-corner-all'></input>" +
40544 "</div>").dialog({
40545 width:'auto',
40546 buttons: [
40547 {
40548 text: "save",
40549 click: function(){
40550 var saveName = $("#saveName").val();
40551 var saveObject = new Object();
40552 saveObject.type = pieChart.type;
40553 saveObject.categories = pieChart.categories;
40554 saveObject.columnName = pieChart.watchColumn;
40555 //save to LocalStorage
40556 $.remember({
40557 name:pieChart.options.localStoragePrefix+saveName,
40558 value:saveObject,
40559 json:true
40560 });
40561 $(this).dialog( "close" );
40562 }
40563 }
40564 ]
40565 });
40566
40567 //set value to default (column name)
40568 $("#saveName").val(pieChart.watchColumn);
40569 //TODO: z-index has to be set, as the "tool-bars" of map (.ddbToolbar in style.css)
40570 //also have a z-index of 10000. z-index should be removed from all elements.
40571 $(".ui-dialog").css("z-index",10005);
40572 });
40573 }
40574 }
40575
40576 $(this.parent.gui.pieChartsDiv).append(this.informationDIV);
40577 this.pieChartDiv = document.createElement("div");
40578 $(this.parent.gui.pieChartsDiv).append(this.pieChartDiv);
40579
40580 $(this.pieChartDiv).unbind();
40581 $(this.pieChartDiv).bind("plothover", function (event, pos, item) {
40582 var highlightedLabel;
40583
40584 if (item) {
40585 highlightedLabel = item.series.label;
40586 }
40587 if (highlightedLabel !== pieChart.highlightedLabel){
40588 pieChart.highlightedLabel = highlightedLabel;
40589 pieChart.triggerHighlight(highlightedLabel);
40590 }
40591 });
40592
40593 $(this.pieChartDiv).bind("plotclick", function (event, pos, item) {
40594 if (item) {
40595 //item.series.label contains the column element
40596 pieChart.triggerSelection(item.series.label);
40597 } else {
40598 pieChart.triggerSelection();
40599 }
40600 });
40601 }
40602 },
40603
40604 //check if dataset is still there
40605 checkForDataSet : function() {
40606 var datasets = this.parent.datasets;
40607 if ((typeof datasets !== "undefined") && (typeof this.watchedDatasetObject !== "undefined")){
40608 //check if our data went missing
40609 for (var i = 0; i < datasets.length; i++){
40610 if (datasets[i] === this.watchedDatasetObject){
40611 //if dataset "before" this one was removed, the index changes
40612 if (this.watchedDataset !== i){
40613 //change color to the new one (changes with index!)
40614 this.watchedDataset = i;
40615 this.refreshLabel();
40616 }
40617 return true;
40618 }
40619 }
40620 }
40621 return false;
40622 },
40623
40624 initPieChart : function(dataSets) {
40625 // get dataset object (could not be there on startup, e.g. piechart defined before load completes)
40626 if (typeof this.watchedDatasetObject === "undefined")
40627 this.watchedDatasetObject = this.parent.datasets[this.watchedDataset];
40628
40629 this.initialize();
40630
40631 // if our dataset went missing, remove this piechart
40632 if (!this.checkForDataSet()){
40633 this.remove();
40634 return;
40635 }
40636
40637 var objects = [];
40638 for (var i = 0; i < dataSets.length; i++)
40639 objects.push([]);
40640 objects[this.watchedDataset] = dataSets[this.watchedDataset].objects;
40641
40642 this.preHighlightObjects = objects;
40643 this.redrawPieChart(objects);
40644 },
40645
40646 redrawPieChart : function(objects) {
40647
40648 if (typeof objects === "undefined")
40649 objects = this.preHighlightObjects;
40650
40651 if (this.checkForDataSet(objects)){
40652 var pieChart = this;
40653 if (objects[this.watchedDataset].length === 0)
40654 objects = this.preHighlightObjects;
40655
40656 var calculateSlices = function(dataObjects){
40657 var chartDataCounter = new Object;
40658
40659 $(dataObjects).each(function(){
40660 var columnData = pieChart.parent.getElementData(this, pieChart.watchColumn, pieChart.selectionFunction);
40661
40662 //disregard empty cells
40663 if ( (typeof columnData === "undefined") || (columnData == "") )
40664 return;
40665
40666 if (typeof chartDataCounter[columnData] === "undefined")
40667 chartDataCounter[columnData] = 1;
40668 else
40669 chartDataCounter[columnData]++;
40670 });
40671
40672 var chartData = [];
40673 $.each(chartDataCounter, function(name,val){
40674 //get rgb-color (24bit = 6 hex digits) from hash
40675 var color = '#'+hex_md5(name).substr(0,6);
40676 chartData.push({label:name,data:val,color:color});
40677 });
40678
40679 //sort by count (occurances of category)
40680 var sortByVal = function(a,b){
40681 return (b.data-a.data);
40682 };
40683 chartData.sort(sortByVal);
40684
40685 return chartData;
40686 };
40687
40688 var chartData = calculateSlices(objects[this.watchedDataset]);
40689
40690 if (chartData.length>0){
40691 $(this.pieChartDiv).empty();
40692
40693 //calculate height (flot NEEDS a height)
40694 var parentHeight = $(this.parent.gui.pieChartsDiv).outerHeight(true) - $(this.parent.gui.columnSelectorDiv).outerHeight(true);
40695 var pieChartCount = 0;
40696 $(this.parent.pieCharts).each(function(){
40697 if (this instanceof PieChart)
40698 pieChartCount++;
40699 });
40700 var height = (parentHeight/pieChartCount) - $(this.informationDIV).outerHeight(true);
40701 if (pieChart.options.restrictPieChartSize !== false)
40702 height = Math.min(height, $(window).height() * pieChart.options.restrictPieChartSize);
40703 $(this.pieChartDiv).height(height);
40704
40705 $.plot($(this.pieChartDiv), chartData,
40706 {
40707 series: {
40708 // Make this a pie chart.
40709 pie: {
40710 show:true
40711 }
40712 },
40713 legend: { show:true, position: 'se' },
40714 grid: {
40715 hoverable: true,
40716 clickable: true
40717 },
40718 tooltip: true,
40719 tooltipOpts: {
40720 content: "%s %p.1%"
40721 }
40722 }
40723 );
40724 }
40725 }
40726 },
40727
40728 triggerHighlight : function(columnElement) {
40729 var highlightedObjects = [];
40730 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
40731 highlightedObjects.push([]);
40732
40733 if (this.watchedDataset >= 0)
40734 highlightedObjects[this.watchedDataset] =
40735 this.parent.getElementsByValue(columnElement, this.watchedDataset, this.watchColumn, this.selectionFunction);
40736 else
40737 highlightedObjects[this.watchedDataset] = [];
40738
40739 this.parent.core.triggerHighlight(highlightedObjects);
40740
40741 var pieChart = this;
40742 $(this.parent.pieCharts).each(function(){
40743 if (this instanceof PieChart && (this !== pieChart)){
40744 if (this.watchedDataset === pieChart.watchedDataset)
40745 this.redrawPieChart(highlightedObjects);
40746 }
40747 });
40748 },
40749
40750 triggerSelection : function(columnElement) {
40751 var selectedObjects = [];
40752 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
40753 selectedObjects.push([]);
40754
40755 var selection;
40756 if (typeof columnElement !== "undefined"){
40757 selectedObjects[this.watchedDataset] =
40758 this.parent.getElementsByValue(columnElement, this.watchedDataset, this.watchColumn, this.selectionFunction);
40759 selection = new Selection(selectedObjects, this);
40760 } else {
40761 selection = new Selection(selectedObjects);
40762 }
40763
40764 this.parent.core.triggerSelection(selection);
40765
40766 if (!selection.valid()){
40767 selection.loadAllObjects();
40768 //"undo" selection (click next to piechart)
40769 //so also redraw this dataset
40770 this.preHighlightObjects = selection.objects;
40771 this.redrawPieChart(selection.objects);
40772 }
40773
40774 var pieChart = this;
40775 $(this.parent.pieCharts).each(function(){
40776 if (this instanceof PieChart && (this !== pieChart)){
40777 if (this.watchedDataset === pieChart.watchedDataset){
40778 this.preHighlightObjects = selection.objects;
40779 this.redrawPieChart(selection.objects);
40780 }
40781 }
40782 });
40783 },
40784
40785 deselection : function() {
40786 },
40787
40788 filtering : function() {
40789 },
40790
40791 inverseFiltering : function() {
40792 },
40793
40794 triggerRefining : function() {
40795 },
40796
40797 reset : function() {
40798 },
40799
40800 show : function() {
40801 },
40802
40803 hide : function() {
40804 }
40805 };
40806 /*
40807 * PieChartCategoryChooser.js
40808 *
40809 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
40810 *
40811 * This library is free software; you can redistribute it and/or
40812 * modify it under the terms of the GNU Lesser General Public
40813 * License as published by the Free Software Foundation; either
40814 * version 3 of the License, or (at your option) any later version.
40815 *
40816 * This library is distributed in the hope that it will be useful,
40817 * but WITHOUT ANY WARRANTY; without even the implied warranty of
40818 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
40819 * Lesser General Public License for more details.
40820 *
40821 * You should have received a copy of the GNU Lesser General Public
40822 * License along with this library; if not, write to the Free Software
40823 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
40824 * MA 02110-1301 USA
40825 */
40826
40827 /**
40828 * @class PieChartCategoryChooser
40829 * PieChart dialog for category creation
40830 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
40831 *
40832 * @param {PieChartWidget} parent PieChart widget object
40833 * @param {JSON} options PieChart configuration
40834 * @param {number} datasetIndex index of the dataset
40835 * @param {String} columnName name of the column
40836 */
40837
40838 function PieChartCategoryChooser(pieChart, options, datasetIndex, columnName, type, categories) {
40839
40840 var pieChartCategoryChooser = this;
40841
40842 this.parent = pieChart;
40843 this.options = options;
40844 this.datasetIndex = parseInt(datasetIndex);
40845 this.columnName = columnName;
40846 this.chartData;
40847
40848 this.dialog = $("<div></div>");
40849 this.dialog.html("").dialog({modal: true}).dialog('open');
40850
40851 //to asure that the dialog is above (z-index of) the toolbars
40852 $(".ui-front").css("z-index","10001");
40853
40854 var allNumeric = this.loadValues(datasetIndex, columnName);
40855
40856 if (typeof allNumeric === "undefined")
40857 return;
40858 if (allNumeric === true){
40859 this.createNumeralBasedChooser(this.chartData, categories);
40860 } else {
40861 this.createTextBasedChooser(this.chartData, categories);
40862 }
40863 };
40864
40865 PieChartCategoryChooser.prototype = {
40866
40867 loadValues : function(datasetIndex, columnName){
40868 var pieChartCategoryChooser = this;
40869
40870 var allNumeric = true;
40871 pieChartCategoryChooser.chartData = [];
40872 var chartData = pieChartCategoryChooser.chartData;
40873 $(GeoTemConfig.datasets[datasetIndex].objects).each(function(){
40874 var columnData =
40875 pieChartCategoryChooser.parent.getElementData(this, columnName);
40876
40877 if (isNaN(parseFloat(columnData)))
40878 allNumeric = false;
40879
40880 if ($.inArray(columnData, chartData) == -1)
40881 chartData.push(columnData);
40882 });
40883
40884 if (chartData.length === 0)
40885 return;
40886 else
40887 return allNumeric;
40888 },
40889
40890 createTextBasedChooser : function(chartData, categories){
40891 var pieChartCategoryChooser = this;
40892
40893 var addCategory = function(name,elements){
40894 var newCategoryContainer = document.createElement("fieldset");
40895 var newCategoryLegend = document.createElement("legend");
40896 var newCategoryName = document.createElement("input");
40897 $(newCategoryName).width("80%");
40898 newCategoryName.type = "text";
40899 newCategoryName.value = name;
40900 var newCategoryRemove = document.createElement("button");
40901 $(newCategoryRemove).text("X");
40902 $(newCategoryRemove).click(function(){
40903 $(newCategoryContainer).find("li").each(function(){
40904 //move all elements to unselected list
40905 //("unselected" is defined below)
40906 //prepend so the items appear on top
40907 $(this).prependTo(unselected);
40908 });
40909 //and remove this category
40910 $(newCategoryContainer).remove();
40911 });
40912 $(newCategoryLegend).append(newCategoryName);
40913 $(newCategoryLegend).append(newCategoryRemove);
40914 $(newCategoryContainer).append(newCategoryLegend);
40915 $(newCategoryContainer).width("200px");
40916 $(newCategoryContainer).css("float","left");
40917 var newCategory = document.createElement("ul");
40918 $(newCategory).addClass("connectedSortable");
40919 $(newCategory).css("background", "#eee");
40920 newCategoryContainer.appendChild(newCategory);
40921 $(newCategory).append("<br/>");
40922 cell.appendChild(newCategoryContainer);
40923 //if there are pre-selected elements (e.g. "edit")
40924 //add them and remove them from unselected value list
40925 if (typeof elements !== "undefined"){
40926 $(elements).each(function(){
40927 var value = this;
40928 //add to category
40929 $(newCategory).append("<li>"+value+"</li>");
40930 //remove from unselected list
40931 $(unselected).find("li").filter(function(){
40932 return ($(this).text() === ""+value);
40933 }).remove();
40934 });
40935 }
40936
40937 $( ".connectedSortable" ).sortable({
40938 connectWith: ".connectedSortable"
40939 }).disableSelection();
40940 };
40941
40942 var table = document.createElement("table");
40943 var row = document.createElement("tr");
40944 table.appendChild(row);
40945 var cell = document.createElement("td");
40946 row.appendChild(cell);
40947 cell = document.createElement("td");
40948 row.appendChild(cell);
40949 var addCategoryButton = document.createElement("button");
40950 $(addCategoryButton).text("add new category");
40951 cell.appendChild(addCategoryButton);
40952 var applyCategoryButton = document.createElement("button");
40953 $(applyCategoryButton).text("apply");
40954 cell.appendChild(applyCategoryButton);
40955
40956 row = document.createElement("tr");
40957 table.appendChild(row);
40958 cell = document.createElement("td");
40959 row.appendChild(cell);
40960 var unselected = document.createElement("ul");
40961 $(unselected).addClass("connectedSortable");
40962 cell.appendChild(unselected);
40963 cell = document.createElement("td");
40964 $(cell).attr("valign","top");
40965 $(cell).width("100%");
40966 row.appendChild(cell);
40967
40968 this.dialog.append(table);
40969
40970 $( ".connectedSortable" ).sortable({
40971 connectWith: ".connectedSortable"
40972 }).disableSelection();
40973
40974 $(chartData).each(function(){
40975 $(unselected).append("<li class='ui-state-default'>"+this+"</li>");
40976 });
40977
40978 if (typeof categories !== "undefined"){
40979 $(categories).each(function(){
40980 var category = this;
40981 addCategory(category.label, category.values);
40982 });
40983 }
40984
40985 $(addCategoryButton).click(function(){addCategory();});
40986
40987 $(applyCategoryButton).click(function(){
40988 var categories = [];
40989 $(cell).children().each(function(){
40990 var label = $(this).find("legend > input").val();
40991 var values = [];
40992 $(this).find("li").each(function(){
40993 values.push($(this).text());
40994 });
40995
40996 categories.push({label:label,values:values});
40997 });
40998
40999 var values = [];
41000 $(unselected).find("li").each(function(){
41001 values.push($(this).text());
41002 });
41003
41004 categories.push({label:"other",values:values});
41005
41006 //create pie chart
41007 pieChartCategoryChooser.parent.addCategorizedPieChart(
41008 pieChartCategoryChooser.datasetIndex, pieChartCategoryChooser.columnName,
41009 "text", categories);
41010
41011 //close dialog
41012 $(pieChartCategoryChooser.dialog).dialog("close");
41013 });
41014
41015 //set dialog size
41016 var wWidth = $(window).width();
41017 var dWidth = wWidth * 0.9;
41018 var wHeight = $(window).height();
41019 var dHeight = wHeight * 0.9;
41020 $(this.dialog).dialog("option", "width", dWidth);
41021 $(this.dialog).dialog("option", "height", dHeight);
41022 },
41023
41024 createNumeralBasedChooser : function(chartData, existingCategories){
41025 var numericChartData = [];
41026 for (var i = 0; i < chartData.length; i++){
41027 numericChartData.push(parseFloat(chartData[i]));
41028 }
41029 chartData = numericChartData;
41030 chartData = chartData.sort(function sortNumber(a,b){
41031 return a - b;
41032 });
41033
41034 var min = chartData[0];
41035 var max = chartData[chartData.length-1];
41036 //find minimum step width that is needed
41037 //(otherwise there could be steps that contain more than one element)
41038 var minStep=max-min;
41039 for (var i = 1; i < chartData.length; i++){
41040 var thisStep = chartData[i]-chartData[i-1];
41041 if ((thisStep) < minStep)
41042 minStep = thisStep;
41043 }
41044
41045 var pieChartCategoryChooser = this;
41046
41047 var addCategoryButton = document.createElement("button");
41048 $(addCategoryButton).text("add new category");
41049 this.dialog.append(addCategoryButton);
41050 var applyCategoryButton = document.createElement("button");
41051 $(applyCategoryButton).text("apply");
41052 this.dialog.append(applyCategoryButton);
41053 this.dialog.append("tip: use left/right arrow key for finer adjustment");
41054
41055 var table = document.createElement("table");
41056 row = document.createElement("tr");
41057 table.appendChild(row);
41058 cell = document.createElement("td");
41059 row.appendChild(cell);
41060 cell.colSpan = 2;
41061 var slider = document.createElement("div");
41062 cell.appendChild(slider);
41063 var handles = [];
41064 var categories = [];
41065
41066 row = document.createElement("tr");
41067 table.appendChild(row);
41068 cell = document.createElement("td");
41069 $(cell).attr("valign","top");
41070 row.appendChild(cell);
41071 var unselected = document.createElement("ul");
41072 cell.appendChild(unselected);
41073
41074 cell = document.createElement("td");
41075 $(cell).attr("valign","top");
41076 $(cell).width("100%");
41077 row.appendChild(cell);
41078
41079 this.dialog.append(table);
41080
41081 $(chartData).each(function(){
41082 $(unselected).append("<li class='ui-state-default'>"+this+"</li>");
41083 });
41084
41085 var addCategory = function(boundary){
41086 //check if another handle can be added
41087 if ((handles.length>0) && (handles[handles.length-1] === max))
41088 return false;
41089 //destroy old slider (has to be recreated to show the new handle)
41090 if (handles.length>0)
41091 $(slider).slider("destroy");
41092
41093 if (typeof boundary === "undefined")
41094 boundary = max;
41095 handles.push(boundary);
41096
41097 $(slider).slider({
41098 min:min,
41099 max:max,
41100 step:minStep,
41101 values: handles
41102 });
41103
41104 var placeValues = function(){
41105 $(unselected).find("li").remove();
41106 $(cell).children().find("li").remove();
41107
41108 var j = 0, i = 0;
41109 for (; i < chartData.length; i++){
41110 if (chartData[i]>handles[j])
41111 j++;
41112 if (j == handles.length)
41113 break;
41114 $(categories[j]).append("<li class='ui-state-default'>"+chartData[i]+"</li>");
41115 }
41116 for (; i < chartData.length; i++){
41117 $(unselected).append("<li class='ui-state-default'>"+chartData[i]+"</li>");
41118 }
41119 };
41120
41121 $(slider).on( "slide", function( event, ui ){
41122 var last = min;
41123 //check whether handle values are increasing
41124 for(var i = 0; i < ui.values.length; i++){
41125 if (ui.values[i]<last)
41126 return false;
41127 last = ui.values[i];
41128 }
41129 handles = ui.values;
41130 for(var i = 0; i < handles.length; i++){
41131 $(categories[i]).parent().find("legend").text("<="+handles[i]);
41132 }
41133
41134 placeValues();
41135 });
41136
41137 var newCategoryContainer = document.createElement("fieldset");
41138 $(newCategoryContainer).append("<legend><="+boundary+"</legend>");
41139 $(newCategoryContainer).width("188px");
41140 $(newCategoryContainer).css("float","left");
41141 var newCategory = document.createElement("ul");
41142 $(newCategory).addClass("connectedSortable");
41143 $(newCategory).css("background", "#eee");
41144 newCategoryContainer.appendChild(newCategory);
41145 cell.appendChild(newCategoryContainer);
41146 categories.push(newCategory);
41147
41148 placeValues();
41149 };
41150
41151 $(addCategoryButton).click(function(){addCategory();});
41152
41153 if (typeof existingCategories !== "undefined"){
41154 $(existingCategories).each(function(){
41155 var boundary = this;
41156 addCategory(boundary);
41157 });
41158 }
41159
41160 $(applyCategoryButton).click(function(){
41161 var categorieBoundaries = handles;
41162
41163 //create pie chart
41164 pieChartCategoryChooser.parent.addCategorizedPieChart(
41165 pieChartCategoryChooser.datasetIndex, pieChartCategoryChooser.columnName,
41166 "numeral", categorieBoundaries);
41167
41168 //close dialog
41169 $(pieChartCategoryChooser.dialog).dialog("close");
41170 });
41171
41172 //set dialog size
41173 var wWidth = $(window).width();
41174 var dWidth = wWidth * 0.9;
41175 var wHeight = $(window).height();
41176 var dHeight = wHeight * 0.9;
41177 $(this.dialog).dialog("option", "width", dWidth);
41178 $(this.dialog).dialog("option", "height", dHeight);
41179 }
41180 };
41181 /*
41182 * PieChartConfig.js
41183 *
41184 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
41185 *
41186 * This library is free software; you can redistribute it and/or
41187 * modify it under the terms of the GNU Lesser General Public
41188 * License as published by the Free Software Foundation; either
41189 * version 3 of the License, or (at your option) any later version.
41190 *
41191 * This library is distributed in the hope that it will be useful,
41192 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41193 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41194 * Lesser General Public License for more details.
41195 *
41196 * You should have received a copy of the GNU Lesser General Public
41197 * License along with this library; if not, write to the Free Software
41198 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
41199 * MA 02110-1301 USA
41200 */
41201
41202 /**
41203 * @class PieChartConfig
41204 * PieChart Configuration File
41205 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
41206 */
41207 function PieChartConfig(options) {
41208
41209 this.options = {
41210 proxy : 'php/proxy.php?address=',
41211 restrictPieChartSize : 0.25, // restrict size to percantage of window size (false for no restriction)
41212 localStoragePrefix : "GeoBrowser_PieChart_", // prefix for value name in LocalStorage
41213 allowLocalStorage : true, //whether LocalStorage save and load should be allowed (and buttons shown)
41214 };
41215 if ( typeof options != 'undefined') {
41216 $.extend(this.options, options);
41217 }
41218
41219 };
41220 /*
41221 * PieChartGui.js
41222 *
41223 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
41224 *
41225 * This library is free software; you can redistribute it and/or
41226 * modify it under the terms of the GNU Lesser General Public
41227 * License as published by the Free Software Foundation; either
41228 * version 3 of the License, or (at your option) any later version.
41229 *
41230 * This library is distributed in the hope that it will be useful,
41231 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41232 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41233 * Lesser General Public License for more details.
41234 *
41235 * You should have received a copy of the GNU Lesser General Public
41236 * License along with this library; if not, write to the Free Software
41237 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
41238 * MA 02110-1301 USA
41239 */
41240
41241 /**
41242 * @class PieChartGui
41243 * PieChart GUI Implementation
41244 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
41245 *
41246 * @param {PieChartWidget} parent PieChart widget object
41247 * @param {HTML object} div parent div to append the PieChart gui
41248 * @param {JSON} options PieChart configuration
41249 */
41250 function PieChartGui(pieChart, div, options) {
41251
41252 this.parent = pieChart;
41253 this.options = options;
41254 var pieChartGui = this;
41255
41256 this.pieChartContainer = div;
41257 this.pieChartContainer.style.position = 'relative';
41258
41259 this.columnSelectorDiv = document.createElement("div");
41260 div.appendChild(this.columnSelectorDiv);
41261 this.datasetSelect = document.createElement("select");
41262 $(this.datasetSelect).change(function(event){
41263 if (typeof pieChartGui.parent.datasets !== "undefined"){
41264 var dataset = pieChartGui.parent.datasets[$(pieChartGui.datasetSelect).val()];
41265 if (dataset.objects.length > 0){
41266 //This implies that the dataObjects are homogenous
41267 var firstObject = dataset.objects[0];
41268 var firstTableContent = firstObject.tableContent;
41269 $(pieChartGui.columnSelect).empty();
41270
41271 $(pieChartGui.columnSelect).append("<optgroup label='saved'>");
41272
41273 for(var key in localStorage){
41274 //TODO: this is a somewhat bad idea, as it is used in multiple widgets.
41275 //A global GeoTemCo option "prefix" could be better. But still..
41276 var prefix = pieChartGui.options.localStoragePrefix;
41277 if (key.startsWith(prefix)){
41278 var saveObject = $.remember({name:key,json:true});
41279 var label = key.substring(prefix.length);
41280 //small safety-check: if the column is not part of this dataset, don't show it
41281 if (typeof firstTableContent[saveObject.columnName] !== "undefined")
41282 $(pieChartGui.columnSelect).append("<option isSaved=1 value='"+label+"'>"+decodeURIComponent(label)+"</option>");
41283 }
41284 }
41285 $(pieChartGui.columnSelect).append("</optgroup>");
41286
41287 $(pieChartGui.columnSelect).append("<optgroup label='new'>");
41288 for (var attribute in firstTableContent) {
41289 $(pieChartGui.columnSelect).append("<option value='"+attribute+"'>"+attribute+"</option>");
41290 }
41291 if (firstObject.isTemporal)
41292 $(pieChartGui.columnSelect).append("<option value='dates[0].date'>date</option>");
41293 if (typeof firstObject.locations[0] !== "undefined"){
41294 $(pieChartGui.columnSelect).append("<option value='locations[0].latitude'>lat</option>");
41295 $(pieChartGui.columnSelect).append("<option value='locations[0].longitude'>lon</option>");
41296 }
41297 $(pieChartGui.columnSelect).append("</optgroup>");
41298 }
41299 }
41300 });
41301 this.columnSelectorDiv.appendChild(this.datasetSelect);
41302 this.columnSelect = document.createElement("select");
41303 this.columnSelectorDiv.appendChild(this.columnSelect);
41304 this.buttonNewPieChart = document.createElement("button");
41305 $(this.buttonNewPieChart).text("add");
41306 this.columnSelectorDiv.appendChild(this.buttonNewPieChart);
41307 $(this.buttonNewPieChart).click(function(){
41308 //check if this is a local saved pie chart
41309 var isSaved=$(pieChartGui.columnSelect).find("option:selected").first().attr("isSaved");
41310 if ((typeof isSaved === "undefined") || (isSaved!=1)){
41311 //create new pie chart (where each value is its own category)
41312 pieChartGui.parent.addPieChart($(pieChartGui.datasetSelect).val(), $(pieChartGui.columnSelect).val());
41313 } else {
41314 //is local saved, get value
41315 var name = pieChartGui.options.localStoragePrefix + $(pieChartGui.columnSelect).val();
41316 var saveObject = $.remember({name:name,json:true});
41317 if ((typeof saveObject !== "undefined") && (saveObject != null)){
41318 var categories = saveObject.categories;
41319 var type = saveObject.type;
41320 var columnName = saveObject.columnName;
41321
41322 //create pie chart
41323 pieChartGui.parent.addCategorizedPieChart(
41324 $(pieChartGui.datasetSelect).val(), columnName,
41325 type, categories);
41326 }
41327 }
41328 });
41329 this.buttonPieChartCategoryChooser = document.createElement("button");
41330 $(this.buttonPieChartCategoryChooser).text("categorize");
41331 this.columnSelectorDiv.appendChild(this.buttonPieChartCategoryChooser);
41332 $(this.buttonPieChartCategoryChooser).click(function(){
41333 //check if this is a local saved pie chart
41334 var isSaved=$(pieChartGui.columnSelect).find("option:selected").first().attr("isSaved");
41335 if ((typeof isSaved === "undefined") || (isSaved!=1)){
41336 var chooser = new PieChartCategoryChooser( pieChartGui.parent,
41337 pieChartGui.options,
41338 $(pieChartGui.datasetSelect).val(),
41339 $(pieChartGui.columnSelect).val() );
41340 } else {
41341 alert("Saved datasets can not be categorized again. Try loading and editing instead.");
41342 }
41343 });
41344
41345 this.refreshColumnSelector();
41346
41347 this.pieChartsDiv = document.createElement("div");
41348 this.pieChartsDiv.id = "pieChartsDivID";
41349 div.appendChild(this.pieChartsDiv);
41350 $(this.pieChartsDiv).height("100%");
41351 };
41352
41353 PieChartGui.prototype = {
41354
41355 refreshColumnSelector : function(){
41356 $(this.datasetSelect).empty();
41357 $(this.columnSelect).empty();
41358
41359 if ( (typeof this.parent.datasets !== "undefined") && (this.parent.datasets.length > 0)) {
41360 var index = 0;
41361 var pieChartGui = this;
41362 $(this.parent.datasets).each(function(){
41363 $(pieChartGui.datasetSelect).append("<option value="+index+">"+this.label+"</option>");
41364 index++;
41365 });
41366
41367 $(pieChartGui.datasetSelect).change();
41368 }
41369 }
41370 };
41371 /*
41372 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
41373 * Digest Algorithm, as defined in RFC 1321.
41374 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
41375 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
41376 * Distributed under the BSD License
41377 * See http://pajhome.org.uk/crypt/md5 for more info.
41378 */
41379
41380 /*
41381 * Configurable variables. You may need to tweak these to be compatible with
41382 * the server-side, but the defaults work in most cases.
41383 */
41384 var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */
41385 var b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */
41386
41387 /*
41388 * These are the functions you'll usually want to call
41389 * They take string arguments and return either hex or base-64 encoded strings
41390 */
41391 function hex_md5(s) { return rstr2hex(rstr_md5(str2rstr_utf8(s))); }
41392 function b64_md5(s) { return rstr2b64(rstr_md5(str2rstr_utf8(s))); }
41393 function any_md5(s, e) { return rstr2any(rstr_md5(str2rstr_utf8(s)), e); }
41394 function hex_hmac_md5(k, d)
41395 { return rstr2hex(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
41396 function b64_hmac_md5(k, d)
41397 { return rstr2b64(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d))); }
41398 function any_hmac_md5(k, d, e)
41399 { return rstr2any(rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d)), e); }
41400
41401 /*
41402 * Perform a simple self-test to see if the VM is working
41403 */
41404 function md5_vm_test()
41405 {
41406 return hex_md5("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
41407 }
41408
41409 /*
41410 * Calculate the MD5 of a raw string
41411 */
41412 function rstr_md5(s)
41413 {
41414 return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
41415 }
41416
41417 /*
41418 * Calculate the HMAC-MD5, of a key and some data (raw strings)
41419 */
41420 function rstr_hmac_md5(key, data)
41421 {
41422 var bkey = rstr2binl(key);
41423 if(bkey.length > 16) bkey = binl_md5(bkey, key.length * 8);
41424
41425 var ipad = Array(16), opad = Array(16);
41426 for(var i = 0; i < 16; i++)
41427 {
41428 ipad[i] = bkey[i] ^ 0x36363636;
41429 opad[i] = bkey[i] ^ 0x5C5C5C5C;
41430 }
41431
41432 var hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
41433 return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
41434 }
41435
41436 /*
41437 * Convert a raw string to a hex string
41438 */
41439 function rstr2hex(input)
41440 {
41441 try { hexcase } catch(e) { hexcase=0; }
41442 var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
41443 var output = "";
41444 var x;
41445 for(var i = 0; i < input.length; i++)
41446 {
41447 x = input.charCodeAt(i);
41448 output += hex_tab.charAt((x >>> 4) & 0x0F)
41449 + hex_tab.charAt( x & 0x0F);
41450 }
41451 return output;
41452 }
41453
41454 /*
41455 * Convert a raw string to a base-64 string
41456 */
41457 function rstr2b64(input)
41458 {
41459 try { b64pad } catch(e) { b64pad=''; }
41460 var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41461 var output = "";
41462 var len = input.length;
41463 for(var i = 0; i < len; i += 3)
41464 {
41465 var triplet = (input.charCodeAt(i) << 16)
41466 | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
41467 | (i + 2 < len ? input.charCodeAt(i+2) : 0);
41468 for(var j = 0; j < 4; j++)
41469 {
41470 if(i * 8 + j * 6 > input.length * 8) output += b64pad;
41471 else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
41472 }
41473 }
41474 return output;
41475 }
41476
41477 /*
41478 * Convert a raw string to an arbitrary string encoding
41479 */
41480 function rstr2any(input, encoding)
41481 {
41482 var divisor = encoding.length;
41483 var i, j, q, x, quotient;
41484
41485 /* Convert to an array of 16-bit big-endian values, forming the dividend */
41486 var dividend = Array(Math.ceil(input.length / 2));
41487 for(i = 0; i < dividend.length; i++)
41488 {
41489 dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
41490 }
41491
41492 /*
41493 * Repeatedly perform a long division. The binary array forms the dividend,
41494 * the length of the encoding is the divisor. Once computed, the quotient
41495 * forms the dividend for the next step. All remainders are stored for later
41496 * use.
41497 */
41498 var full_length = Math.ceil(input.length * 8 /
41499 (Math.log(encoding.length) / Math.log(2)));
41500 var remainders = Array(full_length);
41501 for(j = 0; j < full_length; j++)
41502 {
41503 quotient = Array();
41504 x = 0;
41505 for(i = 0; i < dividend.length; i++)
41506 {
41507 x = (x << 16) + dividend[i];
41508 q = Math.floor(x / divisor);
41509 x -= q * divisor;
41510 if(quotient.length > 0 || q > 0)
41511 quotient[quotient.length] = q;
41512 }
41513 remainders[j] = x;
41514 dividend = quotient;
41515 }
41516
41517 /* Convert the remainders to the output string */
41518 var output = "";
41519 for(i = remainders.length - 1; i >= 0; i--)
41520 output += encoding.charAt(remainders[i]);
41521
41522 return output;
41523 }
41524
41525 /*
41526 * Encode a string as utf-8.
41527 * For efficiency, this assumes the input is valid utf-16.
41528 */
41529 function str2rstr_utf8(input)
41530 {
41531 var output = "";
41532 var i = -1;
41533 var x, y;
41534
41535 while(++i < input.length)
41536 {
41537 /* Decode utf-16 surrogate pairs */
41538 x = input.charCodeAt(i);
41539 y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
41540 if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
41541 {
41542 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
41543 i++;
41544 }
41545
41546 /* Encode output as utf-8 */
41547 if(x <= 0x7F)
41548 output += String.fromCharCode(x);
41549 else if(x <= 0x7FF)
41550 output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
41551 0x80 | ( x & 0x3F));
41552 else if(x <= 0xFFFF)
41553 output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
41554 0x80 | ((x >>> 6 ) & 0x3F),
41555 0x80 | ( x & 0x3F));
41556 else if(x <= 0x1FFFFF)
41557 output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
41558 0x80 | ((x >>> 12) & 0x3F),
41559 0x80 | ((x >>> 6 ) & 0x3F),
41560 0x80 | ( x & 0x3F));
41561 }
41562 return output;
41563 }
41564
41565 /*
41566 * Encode a string as utf-16
41567 */
41568 function str2rstr_utf16le(input)
41569 {
41570 var output = "";
41571 for(var i = 0; i < input.length; i++)
41572 output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
41573 (input.charCodeAt(i) >>> 8) & 0xFF);
41574 return output;
41575 }
41576
41577 function str2rstr_utf16be(input)
41578 {
41579 var output = "";
41580 for(var i = 0; i < input.length; i++)
41581 output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
41582 input.charCodeAt(i) & 0xFF);
41583 return output;
41584 }
41585
41586 /*
41587 * Convert a raw string to an array of little-endian words
41588 * Characters >255 have their high-byte silently ignored.
41589 */
41590 function rstr2binl(input)
41591 {
41592 var output = Array(input.length >> 2);
41593 for(var i = 0; i < output.length; i++)
41594 output[i] = 0;
41595 for(var i = 0; i < input.length * 8; i += 8)
41596 output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
41597 return output;
41598 }
41599
41600 /*
41601 * Convert an array of little-endian words to a string
41602 */
41603 function binl2rstr(input)
41604 {
41605 var output = "";
41606 for(var i = 0; i < input.length * 32; i += 8)
41607 output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
41608 return output;
41609 }
41610
41611 /*
41612 * Calculate the MD5 of an array of little-endian words, and a bit length.
41613 */
41614 function binl_md5(x, len)
41615 {
41616 /* append padding */
41617 x[len >> 5] |= 0x80 << ((len) % 32);
41618 x[(((len + 64) >>> 9) << 4) + 14] = len;
41619
41620 var a = 1732584193;
41621 var b = -271733879;
41622 var c = -1732584194;
41623 var d = 271733878;
41624
41625 for(var i = 0; i < x.length; i += 16)
41626 {
41627 var olda = a;
41628 var oldb = b;
41629 var oldc = c;
41630 var oldd = d;
41631
41632 a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
41633 d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
41634 c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
41635 b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
41636 a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
41637 d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
41638 c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
41639 b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
41640 a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
41641 d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
41642 c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
41643 b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
41644 a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
41645 d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
41646 c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
41647 b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
41648
41649 a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
41650 d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
41651 c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
41652 b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
41653 a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
41654 d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
41655 c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
41656 b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
41657 a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
41658 d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
41659 c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
41660 b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
41661 a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
41662 d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
41663 c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
41664 b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
41665
41666 a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
41667 d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
41668 c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
41669 b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
41670 a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
41671 d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
41672 c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
41673 b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
41674 a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
41675 d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
41676 c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
41677 b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
41678 a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
41679 d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
41680 c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
41681 b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
41682
41683 a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
41684 d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
41685 c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
41686 b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
41687 a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
41688 d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
41689 c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
41690 b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
41691 a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
41692 d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
41693 c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
41694 b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
41695 a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
41696 d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
41697 c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
41698 b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
41699
41700 a = safe_add(a, olda);
41701 b = safe_add(b, oldb);
41702 c = safe_add(c, oldc);
41703 d = safe_add(d, oldd);
41704 }
41705 return Array(a, b, c, d);
41706 }
41707
41708 /*
41709 * These functions implement the four basic operations the algorithm uses.
41710 */
41711 function md5_cmn(q, a, b, x, s, t)
41712 {
41713 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
41714 }
41715 function md5_ff(a, b, c, d, x, s, t)
41716 {
41717 return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
41718 }
41719 function md5_gg(a, b, c, d, x, s, t)
41720 {
41721 return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
41722 }
41723 function md5_hh(a, b, c, d, x, s, t)
41724 {
41725 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
41726 }
41727 function md5_ii(a, b, c, d, x, s, t)
41728 {
41729 return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
41730 }
41731
41732 /*
41733 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
41734 * to work around bugs in some JS interpreters.
41735 */
41736 function safe_add(x, y)
41737 {
41738 var lsw = (x & 0xFFFF) + (y & 0xFFFF);
41739 var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
41740 return (msw << 16) | (lsw & 0xFFFF);
41741 }
41742
41743 /*
41744 * Bitwise rotate a 32-bit number to the left.
41745 */
41746 function bit_rol(num, cnt)
41747 {
41748 return (num << cnt) | (num >>> (32 - cnt));
41749 }
41750 /*
41751 * PieChartWidget.js
41752 *
41753 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
41754 *
41755 * This library is free software; you can redistribute it and/or
41756 * modify it under the terms of the GNU Lesser General Public
41757 * License as published by the Free Software Foundation; either
41758 * version 3 of the License, or (at your option) any later version.
41759 *
41760 * This library is distributed in the hope that it will be useful,
41761 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41762 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41763 * Lesser General Public License for more details.
41764 *
41765 * You should have received a copy of the GNU Lesser General Public
41766 * License along with this library; if not, write to the Free Software
41767 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
41768 * MA 02110-1301 USA
41769 */
41770
41771 /**
41772 * @class PieChartWidget
41773 * PieChartWidget Implementation
41774 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
41775 *
41776 * @param {WidgetWrapper} core wrapper for interaction to other widgets
41777 * @param {HTML object} div parent div to append the PieChart widget div
41778 * @param {JSON} options user specified configuration that overwrites options in PieChartConfig.js
41779 */
41780 PieChartWidget = function(core, div, options) {
41781
41782 this.datasets;
41783 this.selected;
41784 this.core = core;
41785 this.core.setWidget(this);
41786
41787 this.options = (new PieChartConfig(options)).options;
41788 this.gui = new PieChartGui(this, div, this.options);
41789
41790 this.pieCharts = [];
41791 }
41792
41793 PieChartWidget.prototype = {
41794
41795 addCategorizedPieChart : function(watchedDataset, watchedColumn, type, categories){
41796 var selectionFunction;
41797 if (type === "text"){
41798 //create selection function for the pie chart
41799 var selectionFunction = function(columnData){
41800 var categoryLabel;
41801 $(categories).each(function(){
41802 if ($.inArray(columnData,this.values) != -1){
41803 categoryLabel = this.label;
41804 //exit .each
41805 return false;
41806 }
41807 if (typeof categoryLabel !== "undefined")
41808 return false;
41809 });
41810
41811 if (typeof categoryLabel === "undefined")
41812 categoryLabel = "unknown";
41813
41814 return categoryLabel;
41815 };
41816 } else if (type === "numeral"){
41817 //create selection function for the pie chart
41818 var selectionFunction = function(columnData){
41819 var categoryLabel;
41820 var columnDataNumeric = parseFloat(columnData);
41821 for (var i = 0; i < categories.length; i++){
41822 if (columnDataNumeric<=categories[i]){
41823 categoryLabel = pieChartCategoryChooser.columnName + "<=" + categories[i];
41824 break;
41825 }
41826 }
41827
41828 if (typeof categoryLabel === "undefined")
41829 categoryLabel = "unknown";
41830
41831 return categoryLabel;
41832 };
41833 } else
41834 return;
41835
41836 //make categories easy accessible for later usage
41837 selectionFunction.type = type;
41838 selectionFunction.categories = categories;
41839
41840 this.addPieChart(watchedDataset, watchedColumn, selectionFunction);
41841 },
41842
41843 addPieChart : function(watchedDataset, watchedColumn, selectionFunction){
41844 var newPieChart = new PieChart(this, watchedDataset, watchedColumn, selectionFunction);
41845 this.pieCharts.push(newPieChart);
41846 if ( (typeof GeoTemConfig.datasets !== "undefined") &&
41847 (GeoTemConfig.datasets.length > watchedDataset) )
41848 newPieChart.initPieChart(GeoTemConfig.datasets);
41849 this.redrawPieCharts(this.selected);
41850 },
41851
41852 initWidget : function(data) {
41853 var piechart = this;
41854 this.datasets = data;
41855 piechart.selected = [];
41856 $(this.datasets).each(function(){
41857 piechart.selected.push(this.objects);
41858 })
41859
41860 this.gui.refreshColumnSelector();
41861
41862 $(this.pieCharts).each(function(){
41863 if (this instanceof PieChart)
41864 this.initPieChart(data);
41865 });
41866 },
41867
41868 redrawPieCharts : function(objects, overwrite) {
41869 $(this.pieCharts).each(function(){
41870 if (this instanceof PieChart){
41871 if ( (typeof overwrite !== "undefined") && overwrite)
41872 this.preHighlightObjects = objects;
41873 this.redrawPieChart(objects);
41874 }
41875 });
41876 },
41877
41878 highlightChanged : function(objects) {
41879 if( !GeoTemConfig.highlightEvents ){
41880 return;
41881 }
41882 if ( (typeof objects === "undefined") || (objects.length == 0) ){
41883 return;
41884 }
41885 this.redrawPieCharts(objects, false);
41886 },
41887
41888 selectionChanged : function(selection) {
41889 if( !GeoTemConfig.selectionEvents ){
41890 return;
41891 }
41892 if (!selection.valid()){
41893 selection.loadAllObjects();
41894 }
41895 var objects = selection.objects;
41896 this.selected = objects;
41897 this.redrawPieCharts(objects, true);
41898 },
41899
41900 getElementData : function(dataObject, watchedColumn, selectionFunction) {
41901 var columnData;
41902 if (watchedColumn.indexOf("[") === -1){
41903 columnData = dataObject[watchedColumn];
41904 if (typeof columnData === "undefined"){
41905 columnData = dataObject.tableContent[watchedColumn];
41906 };
41907 } else {
41908 try {
41909 var columnName = watchedColumn.split("[")[0];
41910 var IndexAndAttribute = watchedColumn.split("[")[1];
41911 if (IndexAndAttribute.indexOf("]") != -1){
41912 var arrayIndex = IndexAndAttribute.split("]")[0];
41913 var attribute = IndexAndAttribute.split("]")[1];
41914
41915 if (typeof attribute === "undefined")
41916 columnData = dataObject[columnName][arrayIndex];
41917 else{
41918 attribute = attribute.split(".")[1];
41919 columnData = dataObject[columnName][arrayIndex][attribute];
41920 }
41921 }
41922 } catch(e) {
41923 if (typeof console !== undefined)
41924 console.error(e);
41925
41926 delete columnData;
41927 }
41928 }
41929
41930 if ( (typeof columnData !== "undefined") && (typeof selectionFunction !== "undefined") )
41931 columnData = selectionFunction(columnData);
41932
41933 return(columnData);
41934 },
41935
41936 getElementsByValue : function(columnValue, watchedDataset, watchedColumn, selectionFunction) {
41937 var elements = [];
41938 var pieChart = this;
41939
41940 $(this.datasets[watchedDataset].objects).each(function(){
41941 var columnData = pieChart.getElementData(this, watchedColumn, selectionFunction);
41942 if (columnData === columnValue)
41943 elements.push(this);
41944 });
41945
41946 return elements;
41947 },
41948 };
41949 /*
41950 * Storytelling.js
41951 *
41952 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
41953 *
41954 * This library is free software; you can redistribute it and/or
41955 * modify it under the terms of the GNU Lesser General Public
41956 * License as published by the Free Software Foundation; either
41957 * version 3 of the License, or (at your option) any later version.
41958 *
41959 * This library is distributed in the hope that it will be useful,
41960 * but WITHOUT ANY WARRANTY; without even the implied warranty of
41961 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41962 * Lesser General Public License for more details.
41963 *
41964 * You should have received a copy of the GNU Lesser General Public
41965 * License along with this library; if not, write to the Free Software
41966 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
41967 * MA 02110-1301 USA
41968 */
41969
41970 /**
41971 * @class Storytelling
41972 * Implementation of story telling "storage"
41973 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
41974 *
41975 * @param {HTML object} parent div to append the Storytelling widget
41976 */
41977 function Storytelling(parent) {
41978
41979 this.index;
41980 this.storytelling = this;
41981
41982 this.parent = parent;
41983 this.options = parent.options;
41984
41985 this.initialize();
41986 }
41987
41988 Storytelling.prototype = {
41989
41990 remove : function() {
41991 },
41992
41993 initialize : function() {
41994 },
41995
41996 triggerHighlight : function(columnElement) {
41997 },
41998
41999 triggerSelection : function(columnElement) {
42000 },
42001
42002 deselection : function() {
42003 },
42004
42005 filtering : function() {
42006 },
42007
42008 inverseFiltering : function() {
42009 },
42010
42011 triggerRefining : function() {
42012 },
42013
42014 reset : function() {
42015 },
42016
42017 show : function() {
42018 },
42019
42020 hide : function() {
42021 }
42022 };
42023 /*
42024 * StorytellingConfig.js
42025 *
42026 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
42027 *
42028 * This library is free software; you can redistribute it and/or
42029 * modify it under the terms of the GNU Lesser General Public
42030 * License as published by the Free Software Foundation; either
42031 * version 3 of the License, or (at your option) any later version.
42032 *
42033 * This library is distributed in the hope that it will be useful,
42034 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42035 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42036 * Lesser General Public License for more details.
42037 *
42038 * You should have received a copy of the GNU Lesser General Public
42039 * License along with this library; if not, write to the Free Software
42040 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42041 * MA 02110-1301 USA
42042 */
42043
42044 /**
42045 * @class StorytellingConfig
42046 * Storytelling Configuration File
42047 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
42048 */
42049 function StorytellingConfig(options) {
42050
42051 this.options = {
42052 proxy : 'php/proxy.php?address=',
42053 dariahStorage : false,
42054 localStorage : true
42055 };
42056 if ( typeof options != 'undefined') {
42057 $.extend(this.options, options);
42058 }
42059
42060 };
42061 /*
42062 * StorytellingGui.js
42063 *
42064 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
42065 *
42066 * This library is free software; you can redistribute it and/or
42067 * modify it under the terms of the GNU Lesser General Public
42068 * License as published by the Free Software Foundation; either
42069 * version 3 of the License, or (at your option) any later version.
42070 *
42071 * This library is distributed in the hope that it will be useful,
42072 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42073 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42074 * Lesser General Public License for more details.
42075 *
42076 * You should have received a copy of the GNU Lesser General Public
42077 * License along with this library; if not, write to the Free Software
42078 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42079 * MA 02110-1301 USA
42080 */
42081
42082 /**
42083 * @class StorytellingGui
42084 * Storytelling GUI Implementation
42085 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
42086 *
42087 * @param {StorytellingWidget} parent Storytelling widget object
42088 * @param {HTML object} div parent div to append the Storytelling gui
42089 * @param {JSON} options Storytelling configuration
42090 */
42091 function StorytellingGui(storytelling, div, options) {
42092
42093 this.parent = storytelling;
42094 var storytellingGui = this;
42095
42096 storytellingGui.storytellingContainer = document.createElement('div');
42097 $(div).append(storytellingGui.storytellingContainer);
42098 storytellingGui.storytellingContainer.style.position = 'relative';
42099 };
42100
42101 StorytellingGui.prototype = {
42102 };
42103 /*
42104 * StorytellingWidget.js
42105 *
42106 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
42107 *
42108 * This library is free software; you can redistribute it and/or
42109 * modify it under the terms of the GNU Lesser General Public
42110 * License as published by the Free Software Foundation; either
42111 * version 3 of the License, or (at your option) any later version.
42112 *
42113 * This library is distributed in the hope that it will be useful,
42114 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42115 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42116 * Lesser General Public License for more details.
42117 *
42118 * You should have received a copy of the GNU Lesser General Public
42119 * License along with this library; if not, write to the Free Software
42120 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42121 * MA 02110-1301 USA
42122 */
42123
42124 /**
42125 * @class StorytellingWidget
42126 * StorytellingWidget Implementation
42127 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
42128 *
42129 * @param {WidgetWrapper} core wrapper for interaction to other widgets
42130 * @param {HTML object} div parent div to append the Storytelling widget div
42131 * @param {JSON} options user specified configuration that overwrites options in StorytellingConfig.js
42132 */
42133 StorytellingWidget = function(core, div, options) {
42134
42135 this.datasets;
42136 this.core = core;
42137 this.core.setWidget(this);
42138 this.currentStatus = new Object();
42139
42140 this.options = (new StorytellingConfig(options)).options;
42141 this.gui = new StorytellingGui(this, div, this.options);
42142
42143 this.datasetLink;
42144
42145 Publisher.Subscribe('mapChanged', this, function(mapName) {
42146 this.client.currentStatus["mapChanged"] = mapName;
42147 this.client.createLink();
42148 });
42149
42150 var currentStatus = $.url().param("currentStatus");
42151 if (typeof currentStatus !== "undefined"){
42152 this.currentStatus = $.deparam(currentStatus);
42153 $.each(this.currentStatus,function(action,data){
42154 Publisher.Publish(action, data, this);
42155 });
42156 }
42157 }
42158
42159 StorytellingWidget.prototype = {
42160
42161 initWidget : function(data) {
42162 var storytellingWidget = this;
42163 var gui = storytellingWidget.gui;
42164
42165 storytellingWidget.datasets = data;
42166
42167 $(gui.storytellingContainer).empty();
42168
42169 var magneticLinkParam = "";
42170 var datasetIndex = 0;
42171 var linkCount = 1;
42172 $(storytellingWidget.datasets).each(function(){
42173 var dataset = this;
42174
42175 if (magneticLinkParam.length > 0)
42176 magneticLinkParam += "&";
42177
42178 var paragraph = $("<p></p>");
42179 paragraph.append(dataset.label);
42180 if (typeof dataset.url !== "undefined"){
42181 //TODO: makes only sense for KML or CSV URLs, so "type" of
42182 //URL should be preserved (in dataset).
42183 //startsWith and endsWith defined in SIMILE Ajax (string.js)
42184 var type="csv";
42185 if (typeof dataset.type !== "undefined")
42186 type = dataset.type;
42187 else {
42188 if (dataset.url.toLowerCase().endsWith("kml"))
42189 type = "kml";
42190 }
42191
42192 magneticLinkParam += type+linkCount+"=";
42193 linkCount++;
42194 magneticLinkParam += dataset.url;
42195
42196 var tableLinkDiv = document.createElement('a');
42197 tableLinkDiv.title = dataset.url;
42198 tableLinkDiv.href = dataset.url;
42199 tableLinkDiv.target = '_';
42200 tableLinkDiv.setAttribute('class', 'externalLink');
42201 paragraph.append(tableLinkDiv);
42202 } else {
42203 if (storytellingWidget.options.dariahStorage){
42204 var uploadToDARIAH = document.createElement('a');
42205 $(uploadToDARIAH).append("Upload to DARIAH Storage");
42206 uploadToDARIAH.title = "";
42207 uploadToDARIAH.href = dataset.url;
42208
42209 var localDatasetIndex = new Number(datasetIndex);
42210 $(uploadToDARIAH).click(function(){
42211 var csv = GeoTemConfig.createCSVfromDataset(localDatasetIndex);
42212 // taken from dariah.storage.js
42213 var storageURL = "http://ref.dariah.eu/storage/"
42214 $.ajax({
42215 url: storageURL,
42216 type: 'POST',
42217 contentType: 'text/csv',
42218 data: csv,
42219 success: function(data, status, xhr) {
42220 var location = xhr.getResponseHeader('Location');
42221 // the dariah storage id
42222 dsid = location.substring(location.lastIndexOf('/')+1);
42223
42224 //add URL to dataset
42225 storytellingWidget.datasets[localDatasetIndex].url = location;
42226 storytellingWidget.datasets[localDatasetIndex].type = "csv";
42227 //refresh list
42228 storytellingWidget.initWidget(storytellingWidget.datasets);
42229 },
42230 error: function (data, text, error) {
42231 alert('error creating new file in dariah storage because ' + text);
42232 console.log(data);
42233 console.log(text);
42234 console.log(error);
42235 }
42236 });
42237 //discard link click-event
42238 return(false);
42239 });
42240 paragraph.append(uploadToDARIAH);
42241 }
42242 // TODO: if layout is more usable, both options could be used ("else" removed)
42243 else if (storytellingWidget.options.localStorage){
42244 var saveToLocalStorage = document.createElement('a');
42245 $(saveToLocalStorage).append("Save to Local Storage");
42246 saveToLocalStorage.title = "";
42247 saveToLocalStorage.href = dataset.url;
42248
42249 var localDatasetIndex = new Number(datasetIndex);
42250 $(saveToLocalStorage).click(function(){
42251 var csv = GeoTemConfig.createCSVfromDataset(localDatasetIndex);
42252
42253 var storageName = "GeoBrowser_dataset_"+GeoTemConfig.datasets[localDatasetIndex].label;
42254 $.remember({
42255 name:storageName,
42256 value:csv
42257 });
42258
42259 //add URL to dataset
42260 storytellingWidget.datasets[localDatasetIndex].url = storageName;
42261 storytellingWidget.datasets[localDatasetIndex].type = "local";
42262 //refresh list
42263 storytellingWidget.initWidget(storytellingWidget.datasets);
42264
42265 //discard link click-event
42266 return(false);
42267 });
42268 paragraph.append(saveToLocalStorage);
42269 }
42270 }
42271
42272 $(gui.storytellingContainer).append(paragraph);
42273 datasetIndex++;
42274 });
42275
42276 this.datasetLink = magneticLinkParam;
42277 this.createLink();
42278 },
42279
42280 createLink : function() {
42281 $(this.gui.storytellingContainer).find('.magneticLink').remove();
42282
42283 var magneticLink = document.createElement('a');
42284 magneticLink.setAttribute('class', 'magneticLink');
42285 $(magneticLink).append("Magnetic Link");
42286 magneticLink.title = "Use this link to reload currently loaded (online) data.";
42287 magneticLink.href = "?"+this.datasetLink;
42288 var currentStatusParam = $.param(this.currentStatus);
42289 if (currentStatusParam.length > 0)
42290 magneticLink.href += "&currentStatus="+currentStatusParam;
42291 magneticLink.target = '_';
42292 $(this.gui.storytellingContainer).prepend(magneticLink);
42293 },
42294
42295 highlightChanged : function(objects) {
42296 },
42297
42298 selectionChanged : function(selection) {
42299 },
42300 };
42301 /*
42302 * DataObject.js
42303 *
42304 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
42305 *
42306 * This library is free software; you can redistribute it and/or
42307 * modify it under the terms of the GNU Lesser General Public
42308 * License as published by the Free Software Foundation; either
42309 * version 3 of the License, or (at your option) any later version.
42310 *
42311 * This library is distributed in the hope that it will be useful,
42312 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42313 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42314 * Lesser General Public License for more details.
42315 *
42316 * You should have received a copy of the GNU Lesser General Public
42317 * License along with this library; if not, write to the Free Software
42318 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42319 * MA 02110-1301 USA
42320 */
42321
42322 /**
42323 * @class DataObject
42324 * GeoTemCo's data object class
42325 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
42326 * @release 1.0
42327 * @release date: 2012-07-27
42328 * @version date: 2012-07-27
42329 *
42330 * @param {String} name name of the data object
42331 * @param {String} description description of the data object
42332 * @param {JSON} locations a list of locations with longitude, latitide and place name
42333 * @param {JSON} dates a list of dates
42334 * @param {float} lon longitude value of the given place
42335 * @param {float} lat latitude value of the given place
42336 * @param {Date} timeStart start time of the data object
42337 * @param {Date} timeEnd end time of the data object
42338 * @param {int} granularity granularity of the given time
42339 * @param {int} weight weight of the time object
42340 * @param {Openlayers.Projection} projection of the coordinates (optional)
42341 */
42342
42343 DataObject = function(name, description, locations, dates, weight, tableContent, projection) {
42344
42345 this.name = $.trim(name);
42346 this.description = $.trim(description);
42347 this.weight = weight;
42348 this.tableContent = new Object();
42349 var objectTableContent = this.tableContent;
42350 for(key in tableContent){
42351 value = tableContent[key];
42352 objectTableContent[$.trim(key)]=$.trim(value);
42353 }
42354
42355 this.percentage = 0;
42356 this.setPercentage = function(percentage) {
42357 this.percentage = percentage;
42358 }
42359
42360 this.locations = [];
42361 var objectLocations = this.locations;
42362 $(locations).each(function(){
42363 objectLocations.push({
42364 latitude:this.latitude,
42365 longitude:this.longitude,
42366 place:$.trim(this.place)
42367 });
42368 });
42369
42370 //Check if locations are valid
42371 if (projection instanceof OpenLayers.Projection){
42372 var tempLocations = [];
42373 $(this.locations).each(function(){
42374 //EPSG:4326 === WGS84
42375 this.latitude = parseFloat(this.latitude);
42376 this.longitude = parseFloat(this.longitude);
42377 if (projection.getCode() === "EPSG:4326"){
42378 if ( (typeof this.latitude === "number") &&
42379 (this.latitude>=-90) &&
42380 (this.latitude<=90) &&
42381 (typeof this.longitude === "number") &&
42382 (this.longitude>=-180) &&
42383 (this.longitude<=180) )
42384 tempLocations.push(this);
42385 else{
42386 if (typeof console !== "undefined")
42387 console.error("Object " + name + " has no valid coordinate. ("+this.latitude+","+this.longitude+")");
42388 }
42389 }
42390 });
42391 this.locations = tempLocations;
42392 }
42393
42394 this.isGeospatial = false;
42395 if ((typeof this.locations !== "undefined") && (this.locations.length > 0)) {
42396 this.isGeospatial = true;
42397 }
42398
42399 this.placeDetails = [];
42400 for (var i = 0; i < this.locations.length; i++) {
42401 this.placeDetails.push(this.locations[i].place.split("/"));
42402 }
42403
42404 this.getLatitude = function(locationId) {
42405 return this.locations[locationId].latitude;
42406 }
42407
42408 this.getLongitude = function(locationId) {
42409 return this.locations[locationId].longitude;
42410 }
42411
42412 this.getPlace = function(locationId, level) {
42413 if (level >= this.placeDetails[locationId].length) {
42414 return this.placeDetails[locationId][this.placeDetails[locationId].length - 1];
42415 }
42416 return this.placeDetails[locationId][level];
42417 }
42418
42419 this.dates = dates;
42420 this.isTemporal = false;
42421 if ((typeof this.dates !== "undefined") && (this.dates.length > 0)) {
42422 this.isTemporal = true;
42423 }
42424
42425 //TODO: allow more than one timespan (as with dates/places)
42426 this.isFuzzyTemporal = false;
42427 if (this.isTemporal) {
42428 this.isTemporal = false;
42429 this.isFuzzyTemporal = true;
42430
42431 var date = this.dates[0].date;
42432 var granularity = this.dates[0].granularity;
42433
42434 this.TimeSpanGranularity = granularity;
42435
42436 if (granularity === SimileAjax.DateTime.YEAR){
42437 this.TimeSpanBegin = moment(date).startOf("year");
42438 this.TimeSpanEnd = moment(date).endOf("year");
42439 } else if (granularity === SimileAjax.DateTime.MONTH){
42440 this.TimeSpanBegin = moment(date).startOf("month");
42441 this.TimeSpanEnd = moment(date).endOf("month");
42442 } else if (granularity === SimileAjax.DateTime.DAY){
42443 this.TimeSpanBegin = moment(date).startOf("day");
42444 this.TimeSpanEnd = moment(date).endOf("day");
42445 } else if (granularity === SimileAjax.DateTime.HOUR){
42446 this.TimeSpanBegin = moment(date).startOf("hour");
42447 this.TimeSpanEnd = moment(date).endOf("hour");
42448 } else if (granularity === SimileAjax.DateTime.MINUTE){
42449 this.TimeSpanBegin = moment(date).startOf("minute");
42450 this.TimeSpanEnd = moment(date).endOf("minute");
42451 } else if (granularity === SimileAjax.DateTime.SECOND){
42452 this.TimeSpanBegin = moment(date).startOf("second");
42453 this.TimeSpanEnd = moment(date).endOf("second");
42454 } else if (granularity === SimileAjax.DateTime.MILLISECOND){
42455 //this is a "real" exact time
42456 this.isTemporal = true;
42457 this.isFuzzyTemporal = false;
42458 }
42459 } else if ( (typeof this.tableContent["TimeSpan:begin"] !== "undefined") &&
42460 (typeof this.tableContent["TimeSpan:end"] !== "undefined") ){
42461 //parse according to ISO 8601
42462 //don't use the default "cross browser support" from moment.js
42463 //cause it won't work correctly with negative years
42464 var formats = [ "YYYYYY",
42465 "YYYYYY-MM",
42466 "YYYYYY-MM-DD",
42467 "YYYYYY-MM-DDTHH",
42468 "YYYYYY-MM-DDTHH:mm",
42469 "YYYYYY-MM-DDTHH:mm:ss",
42470 "YYYYYY-MM-DDTHH:mm:ss.SSS"
42471 ];
42472 this.TimeSpanBegin = moment(this.tableContent["TimeSpan:begin"],formats.slice());
42473 this.TimeSpanEnd = moment(this.tableContent["TimeSpan:end"],formats.slice());
42474 if ((this.TimeSpanBegin instanceof Object) && this.TimeSpanBegin.isValid() &&
42475 (this.TimeSpanEnd instanceof Object) && this.TimeSpanEnd.isValid()){
42476 //check whether dates are correctly sorted
42477 if (this.TimeSpanBegin>this.TimeSpanEnd){
42478 //dates are in the wrong order
42479 if (typeof console !== "undefined")
42480 console.error("Object " + this.name + " has wrong fuzzy dating (twisted start/end?).");
42481
42482 } else {
42483 var timeSpanBeginGranularity = formats.indexOf(this.TimeSpanBegin._f);
42484 var timeSpanEndGranularity = formats.indexOf(this.TimeSpanEnd._f);
42485 var timeSpanGranularity = Math.max( timeSpanBeginGranularity,
42486 timeSpanEndGranularity );
42487
42488 //set granularity according to formats above
42489 if (timeSpanGranularity === 0){
42490 this.TimeSpanGranularity = SimileAjax.DateTime.YEAR;
42491 } else if (timeSpanGranularity === 1){
42492 this.TimeSpanGranularity = SimileAjax.DateTime.MONTH;
42493 } else if (timeSpanGranularity === 2){
42494 this.TimeSpanGranularity = SimileAjax.DateTime.DAY;
42495 } else if (timeSpanGranularity === 3){
42496 this.TimeSpanGranularity = SimileAjax.DateTime.HOUR;
42497 } else if (timeSpanGranularity === 4){
42498 this.TimeSpanGranularity = SimileAjax.DateTime.MINUTE;
42499 } else if (timeSpanGranularity === 5){
42500 this.TimeSpanGranularity = SimileAjax.DateTime.SECOND;
42501 } else if (timeSpanGranularity === 6){
42502 this.TimeSpanGranularity = SimileAjax.DateTime.MILLISECOND;
42503 }
42504
42505 if (timeSpanBeginGranularity === 0){
42506 this.TimeSpanBeginGranularity = SimileAjax.DateTime.YEAR;
42507 } else if (timeSpanBeginGranularity === 1){
42508 this.TimeSpanBeginGranularity = SimileAjax.DateTime.MONTH;
42509 } else if (timeSpanBeginGranularity === 2){
42510 this.TimeSpanBeginGranularity = SimileAjax.DateTime.DAY;
42511 } else if (timeSpanBeginGranularity === 3){
42512 this.TimeSpanBeginGranularity = SimileAjax.DateTime.HOUR;
42513 } else if (timeSpanBeginGranularity === 4){
42514 this.TimeSpanBeginGranularity = SimileAjax.DateTime.MINUTE;
42515 } else if (timeSpanBeginGranularity === 5){
42516 this.TimeSpanBeginGranularity = SimileAjax.DateTime.SECOND;
42517 } else if (timeSpanBeginGranularity === 6){
42518 this.TimeSpanBeginGranularity = SimileAjax.DateTime.MILLISECOND;
42519 }
42520
42521 if (timeSpanEndGranularity === 0){
42522 this.TimeSpanEndGranularity = SimileAjax.DateTime.YEAR;
42523 } else if (timeSpanEndGranularity === 1){
42524 this.TimeSpanEndGranularity = SimileAjax.DateTime.MONTH;
42525 } else if (timeSpanEndGranularity === 2){
42526 this.TimeSpanEndGranularity = SimileAjax.DateTime.DAY;
42527 } else if (timeSpanEndGranularity === 3){
42528 this.TimeSpanEndGranularity = SimileAjax.DateTime.HOUR;
42529 } else if (timeSpanEndGranularity === 4){
42530 this.TimeSpanEndGranularity = SimileAjax.DateTime.MINUTE;
42531 } else if (timeSpanEndGranularity === 5){
42532 this.TimeSpanEndGranularity = SimileAjax.DateTime.SECOND;
42533 } else if (timeSpanEndGranularity === 6){
42534 this.TimeSpanEndGranularity = SimileAjax.DateTime.MILLISECOND;
42535 }
42536
42537 if (this.TimeSpanEnd.year()-this.TimeSpanBegin.year() >= 1000)
42538 this.TimeSpanGranularity = SimileAjax.DateTime.MILLENNIUM;
42539 else if (this.TimeSpanEnd.year()-this.TimeSpanBegin.year() >= 100)
42540 this.TimeSpanGranularity = SimileAjax.DateTime.CENTURY;
42541 else if (this.TimeSpanEnd.year()-this.TimeSpanBegin.year() >= 10)
42542 this.TimeSpanGranularity = SimileAjax.DateTime.DECADE;
42543
42544 //also set upper bounds according to granularity
42545 //(lower bound is already correct)
42546 if (timeSpanEndGranularity === 0){
42547 this.TimeSpanEnd.endOf("year");
42548 } else if (timeSpanEndGranularity === 1){
42549 this.TimeSpanEnd.endOf("month");
42550 } else if (timeSpanEndGranularity === 2){
42551 this.TimeSpanEnd.endOf("day");
42552 } else if (timeSpanEndGranularity === 3){
42553 this.TimeSpanEnd.endOf("hour");
42554 } else if (timeSpanEndGranularity === 4){
42555 this.TimeSpanEnd.endOf("minute");
42556 } else if (timeSpanEndGranularity === 5){
42557 this.TimeSpanEnd.endOf("second");
42558 } else if (timeSpanEndGranularity === 6){
42559 //has max accuracy, so no change needed
42560 }
42561
42562 this.isFuzzyTemporal = true;
42563 }
42564 }
42565 }
42566
42567
42568 this.getDate = function(dateId) {
42569 return this.dates[dateId].date;
42570 }
42571
42572 this.getTimeGranularity = function(dateId) {
42573 return this.dates[dateId].granularity;
42574 }
42575
42576 this.setIndex = function(index) {
42577 this.index = index;
42578 }
42579
42580 this.getTimeString = function() {
42581 if (this.timeStart != this.timeEnd) {
42582 return (SimileAjax.DateTime.getTimeString(this.granularity, this.timeStart) + " - " + SimileAjax.DateTime.getTimeString(this.granularity, this.timeEnd));
42583 } else {
42584 return SimileAjax.DateTime.getTimeString(this.granularity, this.timeStart) + "";
42585 }
42586 };
42587
42588 this.contains = function(text) {
42589 var allCombined = this.name + " " + this.description + " " + this.weight + " ";
42590
42591 $.each(this.dates, function(key, value){
42592 $.each(value, function(){
42593 allCombined += this + " ";
42594 });
42595 });
42596
42597 $.each(this.locations, function(key, value){
42598 $.each(value, function(){
42599 allCombined += this + " ";
42600 });
42601 });
42602
42603 $.each(this.tableContent, function(key, value){
42604 allCombined += value + " ";
42605 });
42606
42607 return (allCombined.indexOf(text) != -1);
42608 };
42609
42610 this.hasColorInformation = false;
42611
42612 this.setColor = function(r0,g0,b0,r1,g1,b1) {
42613 this.hasColorInformation = true;
42614
42615 this.color = new Object();
42616 this.color.r0 = r0;
42617 this.color.g0 = g0;
42618 this.color.b0 = b0;
42619 this.color.r1 = r1;
42620 this.color.g1 = g1;
42621 this.color.b1 = b1;
42622 };
42623
42624 this.getColor = function() {
42625 if (!this.hasColorInformation)
42626 return;
42627
42628 color = new Object();
42629 color.r0 = this.r0;
42630 color.g0 = this.g0;
42631 color.b0 = this.b0;
42632 color.r1 = this.r1;
42633 color.g1 = this.g1;
42634 color.b1 = this.b1;
42635
42636 return color;
42637 };
42638
42639 Publisher.Publish('dataobjectAfterCreation', this);
42640 };
42641
42642 /*
42643 * Dataset.js
42644 *
42645 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
42646 *
42647 * This library is free software; you can redistribute it and/or
42648 * modify it under the terms of the GNU Lesser General Public
42649 * License as published by the Free Software Foundation; either
42650 * version 3 of the License, or (at your option) any later version.
42651 *
42652 * This library is distributed in the hope that it will be useful,
42653 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42654 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42655 * Lesser General Public License for more details.
42656 *
42657 * You should have received a copy of the GNU Lesser General Public
42658 * License along with this library; if not, write to the Free Software
42659 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42660 * MA 02110-1301 USA
42661 */
42662
42663 /**
42664 * @class Dataset
42665 * GeoTemCo's Dataset class
42666 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
42667 * @release 1.0
42668 * @release date: 2012-07-27
42669 * @version date: 2012-07-27
42670 *
42671 * @param {Array} objects data item arrays from different datasets
42672 * @param {String} label label for the datasets
42673 */
42674 Dataset = function(objects, label, url, type) {
42675
42676 this.objects = objects;
42677 this.label = label;
42678 this.url = url;
42679 this.type = type;
42680
42681 this.color;
42682
42683 Publisher.Publish('datasetAfterCreation', this);
42684 }
42685 /*
42686 * TimeDataSource.js
42687 *
42688 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
42689 *
42690 * This library is free software; you can redistribute it and/or
42691 * modify it under the terms of the GNU Lesser General Public
42692 * License as published by the Free Software Foundation; either
42693 * version 3 of the License, or (at your option) any later version.
42694 *
42695 * This library is distributed in the hope that it will be useful,
42696 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42697 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
42698 * Lesser General Public License for more details.
42699 *
42700 * You should have received a copy of the GNU Lesser General Public
42701 * License along with this library; if not, write to the Free Software
42702 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
42703 * MA 02110-1301 USA
42704 */
42705
42706 /**
42707 * @class TimeDataSource, TimeSlice, TimeStack
42708 * implementation for aggregation of time items
42709 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
42710 * @release 1.0
42711 * @release date: 2012-07-27
42712 * @version date: 2012-07-27
42713 *
42714 * @param {JSON} options time configuration
42715 */
42716 function TimeDataSource(options) {
42717
42718 this.options = options;
42719 this.timeSlices = [];
42720 this.unit
42721 this.minDate
42722 this.maxDate
42723 this.eventSources
42724 this.events
42725 this.leftSlice
42726 this.rightSlice
42727
42728 this.hashMapping
42729
42730 };
42731
42732 TimeDataSource.prototype = {
42733
42734 findTimeUnits : function(granularity, timeUnit, pixels) {
42735
42736 var time = SimileAjax.DateTime;
42737 this.availableUnits = [];
42738 var givenUnits = SimileAjax.DateTime.gregorianUnitLengths;
42739 for (var i = 0; i < givenUnits.length; i++) {
42740 if (granularity > i) {
42741 continue;
42742 }
42743 var slices = 0;
42744 var t = new Date(this.minDate.getTime());
42745 do {
42746 time.roundDownToInterval(t, i, undefined, 1, 0);
42747 slices++;
42748 time.incrementByInterval(t, i, undefined);
42749 } while( t.getTime() <= this.maxDate.getTime() && slices < pixels+2 );
42750 if (slices > 0 && slices <= pixels) {
42751 this.availableUnits.push({
42752 unit : i,
42753 slices : slices,
42754 label : SimileAjax.DateTime.Strings[GeoTemConfig.language][i]
42755 });
42756 }
42757 }
42758 var unitDiff200 = pixels + 1;
42759 for (var i = 0; i < this.availableUnits.length; i++) {
42760 var diff = Math.abs(this.availableUnits[i].slices - 200);
42761 if (diff < unitDiff200) {
42762 unitDiff200 = diff;
42763 this.unit = this.availableUnits[i].unit;
42764 }
42765 }
42766
42767 },
42768
42769 getUnitIndex : function() {
42770 for (var i = 0; i < this.availableUnits.length; i++) {
42771 if (this.unit == this.availableUnits[i].unit) {
42772 return i;
42773 }
42774 }
42775 return 0;
42776 },
42777
42778 setTimeUnit : function(unit) {
42779 this.unit = unit;
42780 this.initializeSlices();
42781 },
42782
42783 /**
42784 * initializes the TimeDataSource
42785 * @param {Timeplot.ColumnSource[]} dataSources the column sources corresponding to the data sets
42786 * @param {Timeplot.DefaultEventSource[]} eventSources the event sources corresponding to the column sources
42787 * @param {TimeObject[][]} timeObjects an array of time objects of different sets
42788 * @param {SimileAjax.DateTime} granularity the time granularity of the given data
42789 */
42790 initialize : function(dataSources, eventSources, timeObjects, granularity, timeUnit, pixels) {
42791
42792 this.dataSources = dataSources;
42793 this.eventSources = eventSources;
42794 this.timeObjects = timeObjects;
42795
42796 this.minDate = undefined;
42797 this.maxDate = undefined;
42798 this.hashMapping = [];
42799 this.projHashMapping = [];
42800
42801 for (var i = 0; i < timeObjects.length; i++) {
42802 this.hashMapping.push([]);
42803 this.projHashMapping.push([]);
42804 for (var j = 0; j < timeObjects[i].length; j++) {
42805 var o = timeObjects[i][j];
42806 if (o.isTemporal) {
42807 var g = o.dates[this.options.timeIndex].granularity;
42808 //o.getTimeGranularity(this.options.timeIndex);
42809 if (g == null) {
42810 continue;
42811 }
42812 var time = o.dates[this.options.timeIndex].date;
42813 //o.getDate(this.options.timeIndex);
42814 if (this.minDate == undefined || time.getTime() < this.minDate.getTime()) {
42815 this.minDate = time;
42816 }
42817 if (this.maxDate == undefined || time.getTime() > this.maxDate.getTime()) {
42818 this.maxDate = time;
42819 }
42820 }
42821 }
42822 }
42823
42824 if (this.minDate == undefined) {
42825 this.minDate = this.options.defaultMinDate;
42826 this.maxDate = this.options.defaultMaxDate;
42827 }
42828
42829 this.findTimeUnits(granularity, timeUnit, pixels);
42830 this.initializeSlices();
42831
42832 },
42833
42834 initializeSlices : function() {
42835 for (var i = 0; i < this.dataSources.length; i++) {
42836 this.dataSources[i]._range = {
42837 earliestDate : null,
42838 latestDate : null,
42839 min : 0,
42840 max : 0
42841 };
42842 }
42843 this.timeSlices = [];
42844 var time = SimileAjax.DateTime;
42845 var t = new Date(this.minDate.getTime() - 0.9 * time.gregorianUnitLengths[this.unit]);
42846 do {
42847 time.roundDownToInterval(t, this.unit, undefined, 1, 0);
42848 var slice = new TimeSlice(SimileAjax.NativeDateUnit.cloneValue(t), this.timeObjects.length, this.dataSources.length);
42849 this.timeSlices.push(slice);
42850 time.incrementByInterval(t, this.unit, undefined);
42851 } while (t.getTime() <= this.maxDate.getTime() + 1.1 * time.gregorianUnitLengths[this.unit]);
42852
42853 for (var i = 0; i < this.timeObjects.length; i++) {
42854 var projId = i;
42855 if( this.dataSources.length == 1 ){
42856 projId = 0;
42857 }
42858 for (var j = 0; j < this.timeObjects[i].length; j++) {
42859 var o = this.timeObjects[i][j];
42860 if (o.isTemporal) {
42861 var date = o.dates[this.options.timeIndex].date;
42862 //o.getDate(this.options.timeIndex);
42863 for (var k = 0; k < this.timeSlices.length - 1; k++) {
42864 var t1 = this.timeSlices[k].date.getTime();
42865 var t2 = this.timeSlices[k + 1].date.getTime();
42866 var stack = null, projStack = null;
42867 if (date >= t1 && date < t2) {
42868 stack = this.timeSlices[k].getStack(i);
42869 projStack = this.timeSlices[k].getProjStack(projId);
42870 }
42871 if (k == this.timeSlices.length - 2 && date >= t2) {
42872 stack = this.timeSlices[k + 1].getStack(i);
42873 projStack = this.timeSlices[k + 1].getProjStack(projId);
42874 }
42875 if (stack != null) {
42876 stack.addObject(o);
42877 projStack.addObject(o);
42878 this.hashMapping[i][o.index] = stack;
42879 this.projHashMapping[i][o.index] = projStack;
42880 break;
42881 }
42882 }
42883 }
42884 }
42885 }
42886
42887 this.events = [];
42888 for (var i = 0; i < this.eventSources.length; i++) {
42889 var eventSet = [];
42890 for (var j = 0; j < this.timeSlices.length; j++) {
42891 var value = new Array("" + this.timeSlices[j].projStacks[i].value);
42892 eventSet.push({
42893 date : this.timeSlices[j].date,
42894 value : value
42895 });
42896 }
42897 this.eventSources[i].loadData(eventSet);
42898 this.events.push(eventSet);
42899 }
42900
42901 this.leftSlice = 0;
42902 this.rightSlice = this.timeSlices.length - 1;
42903
42904 },
42905
42906 getSliceNumber : function() {
42907 return this.timeSlices.length;
42908 },
42909
42910 /**
42911 * computes the slice index corresponding to a given time
42912 * @param {Date} time the given time
42913 * @return the corresponding slice index
42914 */
42915 getSliceIndex : function(time) {
42916 for (var i = 0; i < this.timeSlices.length; i++) {
42917 if (time == this.timeSlices[i].date) {
42918 return i;
42919 }
42920 }
42921 },
42922
42923 /**
42924 * returns the time of a specific time slice
42925 * @param {int} time the given slice index
42926 * @return the corresponding slice date
42927 */
42928 getSliceTime : function(index) {
42929 return this.timeSlices[index].date;
42930 },
42931
42932 /**
42933 * shifts the actual zoomed range
42934 * @param {int} delta the value to shift (negative for left shift, positive for right shift)
42935 * @return boolean value, if the range could be shifted
42936 */
42937 setShift : function(delta) {
42938 if (delta == 1 && this.leftSlice != 0) {
42939 this.leftSlice--;
42940 this.rightSlice--;
42941 return true;
42942 } else if (delta == -1 && this.rightSlice != this.timeSlices.length - 1) {
42943 this.leftSlice++;
42944 this.rightSlice++;
42945 return true;
42946 } else {
42947 return false;
42948 }
42949 },
42950
42951 /**
42952 * zooms the actual range
42953 * @param {int} delta the value to zoom (negative for zoom out, positive for zoom in)
42954 * @param {Date} time the corresponding time of the actual mouse position on the plot
42955 * @param {Date} leftTime the time of the left border of a selected timerange or null
42956 * @param {Date} rightTime the time of the right border of a selected timerange or null
42957 * @return boolean value, if the range could be zoomed
42958 */
42959 setZoom : function(delta, time, leftTime, rightTime) {
42960 var n1 = 0;
42961 var n2 = 0;
42962 var m = -1;
42963 if (delta > 0) {
42964 m = 1;
42965 if (leftTime != null) {
42966 n1 = this.getSliceIndex(leftTime) - this.leftSlice;
42967 n2 = this.rightSlice - this.getSliceIndex(rightTime);
42968 } else {
42969 slice = this.getSliceIndex(time);
42970 if (slice == this.leftSlice || slice == this.rightSlice) {
42971 return;
42972 }
42973 n1 = slice - 1 - this.leftSlice;
42974 n2 = this.rightSlice - slice - 1;
42975 }
42976 } else if (delta < 0) {
42977
42978 n1 = this.leftSlice;
42979 n2 = this.timeSlices.length - 1 - this.rightSlice;
42980 }
42981
42982 var zoomSlices = 2 * delta;
42983 if (Math.abs(n1 + n2) < Math.abs(zoomSlices)) {
42984 zoomSlices = n1 + n2;
42985 }
42986
42987 if (n1 + n2 == 0) {
42988 return false;
42989 }
42990
42991 var m1 = Math.round(n1 / (n1 + n2) * zoomSlices);
42992 var m2 = zoomSlices - m1;
42993
42994 this.leftSlice += m1;
42995 this.rightSlice -= m2;
42996
42997 return true;
42998 },
42999
43000 /**
43001 * resets the plots by loading data of actual zoomed range
43002 */
43003 reset : function(timeGeometry) {
43004 for (var i = 0; i < this.eventSources.length; i++) {
43005 this.eventSources[i].loadData(this.events[i].slice(this.leftSlice, this.rightSlice + 1));
43006 if (i + 1 < this.eventSources.length) {
43007 timeGeometry._earliestDate = null;
43008 timeGeometry._latestDate = null;
43009 }
43010
43011 }
43012 },
43013
43014 /**
43015 * Getter for actual zoom
43016 * @return actual zoom value
43017 */
43018 getZoom : function() {
43019 if (this.timeSlices == undefined) {
43020 return 0;
43021 }
43022 return Math.round((this.timeSlices.length - 3) / 2) - Math.round((this.rightSlice - this.leftSlice - 2) / 2);
43023 },
43024
43025 /**
43026 * Getter for date of the first timeslice
43027 * @return date of the first timeslice
43028 */
43029 earliest : function() {
43030 return this.timeSlices[0].date;
43031 },
43032
43033 /**
43034 * Getter for date of the last timeslice
43035 * @return date of the last timeslice
43036 */
43037 latest : function() {
43038 return this.timeSlices[this.timeSlices.length - 1].date;
43039 },
43040
43041 setOverlay : function(timeObjects) {
43042 for (var i = 0; i < this.timeSlices.length; i++) {
43043 this.timeSlices[i].reset();
43044 }
43045 for (var j in timeObjects ) {
43046 for (var k in timeObjects[j] ) {
43047 var o = timeObjects[j][k];
43048 if (o.isTemporal) {
43049 if (o.getTimeGranularity(this.options.timeIndex) == null) {
43050 continue;
43051 }
43052 this.hashMapping[j][o.index].overlay += o.weight;
43053 this.projHashMapping[j][o.index].overlay += o.weight;
43054 }
43055 }
43056 }
43057 },
43058
43059 size : function() {
43060 if (this.timeSlices.length == 0) {
43061 return 0;
43062 }
43063 return this.timeSlices[0].stacks.length;
43064 }
43065 };
43066
43067 /**
43068 * small class that represents a time slice of the actual timeplot.
43069 * it has a specific date and contains its corrsponding data objects as well
43070 */
43071 function TimeSlice(date, rows, projRows) {
43072
43073 this.date = date;
43074 this.selected = false;
43075
43076 this.stacks = [];
43077 this.projStacks = [];
43078 for (var i = 0; i < rows; i++) {
43079 this.stacks.push(new TimeStack());
43080 }
43081 for (var i = 0; i < projRows; i++) {
43082 this.projStacks.push(new TimeStack());
43083 }
43084
43085 this.getStack = function(row) {
43086 return this.stacks[row];
43087 };
43088
43089 this.getProjStack = function(row) {
43090 return this.projStacks[row];
43091 };
43092
43093 this.reset = function() {
43094 for (var i in this.projStacks ) {
43095 this.stacks[i].overlay = 0;
43096 this.projStacks[i].overlay = 0;
43097 }
43098 };
43099
43100 this.overlay = function() {
43101 var value = 0;
43102 for (var i in this.projStacks ) {
43103 if (this.projStacks[i].overlay > value) {
43104 value = this.projStacks[i].overlay;
43105 }
43106 }
43107 return value;
43108 };
43109
43110 };
43111
43112 /**
43113 * small class that represents a stack for a time slice which
43114 * holds items for different datasets for the specific time range
43115 */
43116 function TimeStack() {
43117
43118 this.overlay = 0;
43119 this.value = 0;
43120 this.elements = [];
43121
43122 this.addObject = function(object) {
43123 this.elements.push(object);
43124 this.value += object.weight;
43125 };
43126
43127 };
43128 /*
43129 * Binning.js
43130 *
43131 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
43132 *
43133 * This library is free software; you can redistribute it and/or
43134 * modify it under the terms of the GNU Lesser General Public
43135 * License as published by the Free Software Foundation; either
43136 * version 3 of the License, or (at your option) any later version.
43137 *
43138 * This library is distributed in the hope that it will be useful,
43139 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43140 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43141 * Lesser General Public License for more details.
43142 *
43143 * You should have received a copy of the GNU Lesser General Public
43144 * License along with this library; if not, write to the Free Software
43145 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
43146 * MA 02110-1301 USA
43147 */
43148
43149 /**
43150 * @class Binning
43151 * Calculates map aggregation with several binning algorithms
43152 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
43153 * @release 1.0
43154 * @release date: 2012-07-27
43155 * @version date: 2012-07-27
43156 */
43157 Binning = function(map, options) {
43158
43159 this.map = map;
43160 this.options = options;
43161 this.reset();
43162
43163 };
43164
43165 Binning.prototype = {
43166
43167 getSet : function() {
43168 var type = this.options.binning;
43169 if (!type) {
43170 return this.getExactBinning();
43171 } else if (type == 'generic') {
43172 return this.getGenericBinning();
43173 } else if (type == 'square') {
43174 return this.getSquareBinning();
43175 } else if (type == 'hexagonal') {
43176 return this.getHexagonalBinning();
43177 } else if (type == 'triangular') {
43178 return this.getTriangularBinning();
43179 }
43180 },
43181
43182 getExactBinning : function() {
43183 if ( typeof this.binnings['exact'] == 'undefined') {
43184 this.exactBinning();
43185 }
43186 return this.binnings['exact'];
43187 },
43188
43189 getGenericBinning : function() {
43190 if ( typeof this.binnings['generic'] == 'undefined') {
43191 this.genericBinning();
43192 }
43193 return this.binnings['generic'];
43194 },
43195
43196 getSquareBinning : function() {
43197 if ( typeof this.binnings['square'] == 'undefined') {
43198 this.squareBinning();
43199 }
43200 return this.binnings['square'];
43201 },
43202
43203 getHexagonalBinning : function() {
43204 if ( typeof this.binnings['hexagonal'] == 'undefined') {
43205 this.hexagonalBinning();
43206 }
43207 return this.binnings['hexagonal'];
43208 },
43209
43210 getTriangularBinning : function() {
43211 if ( typeof this.binnings['triangular'] == 'undefined') {
43212 this.triangularBinning();
43213 }
43214 return this.binnings['triangular'];
43215 },
43216
43217 reset : function() {
43218 this.zoomLevels = this.map.getNumZoomLevels();
43219 this.binnings = [];
43220 this.minimumRadius = this.options.minimumRadius;
43221 this.maximumRadius = this.minimumRadius;
43222 this.maximumPoints = 0;
43223 this.minArea = 0;
43224 this.maxArea = 0;
43225 },
43226
43227 getMaxRadius : function(size) {
43228 return 4 * Math.log(size) / Math.log(2);
43229 },
43230
43231 setObjects : function(objects) {
43232 this.objects = objects;
43233 for (var i = 0; i < this.objects.length; i++) {
43234 var weight = 0;
43235 for (var j = 0; j < this.objects[i].length; j++) {
43236 if (this.objects[i][j].isGeospatial) {
43237 weight += this.objects[i][j].weight;
43238 }
43239 }
43240 var r = this.getMaxRadius(weight);
43241 if (r > this.maximumRadius) {
43242 this.maximumRadius = r;
43243 this.maximumPoints = weight;
43244 this.maxArea = Math.PI * this.maximumRadius * this.maximumRadius;
43245 this.minArea = Math.PI * this.minimumRadius * this.minimumRadius;
43246 }
43247 }
43248 },
43249
43250 dist : function(x1, y1, x2, y2) {
43251 return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
43252 },
43253
43254 exactBinning : function() {
43255 var circleSets = [];
43256 var hashMaps = [];
43257 var selectionHashs = [];
43258
43259 var circleAggregates = [];
43260 var bins = [];
43261 for (var i = 0; i < this.objects.length; i++) {
43262 bins.push([]);
43263 circleAggregates.push([]);
43264 for (var j = 0; j < this.objects[i].length; j++) {
43265 var o = this.objects[i][j];
43266 if (o.isGeospatial) {
43267 if ( typeof circleAggregates[i]['' + o.getLongitude(this.options.mapIndex)] == 'undefined') {
43268 circleAggregates[i]['' + o.getLongitude(this.options.mapIndex)] = [];
43269 }
43270 if ( typeof circleAggregates[i][''+o.getLongitude(this.options.mapIndex)]['' + o.getLatitude(this.options.mapIndex)] == 'undefined') {
43271 circleAggregates[i][''+o.getLongitude(this.options.mapIndex)]['' + o.getLatitude(this.options.mapIndex)] = [];
43272 bins[i].push(circleAggregates[i][''+o.getLongitude(this.options.mapIndex)]['' + o.getLatitude(this.options.mapIndex)]);
43273 }
43274 circleAggregates[i][''+o.getLongitude(this.options.mapIndex)]['' + o.getLatitude(this.options.mapIndex)].push(o);
43275 }
43276 }
43277 }
43278
43279 var circles = [];
43280 var hashMap = [];
43281 var selectionMap = [];
43282 for (var i = 0; i < bins.length; i++) {
43283 circles.push([]);
43284 hashMap.push([]);
43285 selectionMap.push([]);
43286 for (var j = 0; j < bins[i].length; j++) {
43287 var bin = bins[i][j];
43288 var p = new OpenLayers.Geometry.Point(bin[0].getLongitude(this.options.mapIndex), bin[0].getLatitude(this.options.mapIndex), null);
43289 p.transform(this.map.displayProjection, this.map.projection);
43290 var weight = 0;
43291 for (var z = 0; z < bin.length; z++) {
43292 weight += bin[z].weight;
43293 }
43294 var radius = this.options.minimumRadius;
43295 if (this.options.noBinningRadii == 'dynamic') {
43296 radius = this.getRadius(weight);
43297 }
43298 var circle = new CircleObject(p.x, p.y, 0, 0, bin, radius, i, weight);
43299 circles[i].push(circle);
43300 for (var z = 0; z < bin.length; z++) {
43301 hashMap[i][bin[z].index] = circle;
43302 selectionMap[i][bin[z].index] = false;
43303 }
43304 }
43305 }
43306 for (var k = 0; k < this.zoomLevels; k++) {
43307 circleSets.push(circles);
43308 hashMaps.push(hashMap);
43309 selectionHashs.push(selectionMap);
43310 }
43311 this.binnings['exact'] = {
43312 circleSets : circleSets,
43313 hashMaps : hashMaps,
43314 selectionHashs : selectionHashs
43315 };
43316 },
43317
43318 genericClustering : function(objects, id) {
43319 var binSets = [];
43320 var circleSets = [];
43321 var hashMaps = [];
43322 var selectionHashs = [];
43323 var clustering = new Clustering(-20037508.34, -20037508.34, 20037508.34, 20037508.34);
43324 for (var i = 0; i < objects.length; i++) {
43325 for (var j = 0; j < objects[i].length; j++) {
43326 var o = objects[i][j];
43327 if (o.isGeospatial) {
43328 var p = new OpenLayers.Geometry.Point(o.getLongitude(this.options.mapIndex), o.getLatitude(this.options.mapIndex), null);
43329 p.transform(this.map.displayProjection, this.map.projection);
43330 var point = new Vertex(Math.floor(p.x), Math.floor(p.y), objects.length, this);
43331 point.addElement(o, o.weight, i);
43332 clustering.add(point);
43333 }
43334 }
43335 }
43336
43337 for (var i = 0; i < this.zoomLevels; i++) {
43338 var bins = [];
43339 var circles = [];
43340 var hashMap = [];
43341 var selectionMap = [];
43342 for (var j = 0; j < objects.length; j++) {
43343 circles.push([]);
43344 hashMap.push([]);
43345 selectionMap.push([]);
43346 }
43347 var resolution = this.map.getResolutionForZoom(this.zoomLevels - i - 1);
43348 clustering.mergeForResolution(resolution, this.options.circleGap, this.options.circleOverlap);
43349 for (var j = 0; j < clustering.vertices.length; j++) {
43350 var point = clustering.vertices[j];
43351 if (!point.legal) {
43352 continue;
43353 }
43354 var balls = [];
43355 for (var k = 0; k < point.elements.length; k++) {
43356 if (point.elements[k].length > 0) {
43357 balls.push({
43358 search : k,
43359 elements : point.elements[k],
43360 radius : point.radii[k],
43361 weight : point.weights[k]
43362 });
43363 }
43364 }
43365 var orderBalls = function(b1, b2) {
43366 if (b1.radius > b2.radius) {
43367 return -1;
43368 }
43369 if (b2.radius > b1.radius) {
43370 return 1;
43371 }
43372 return 0;
43373 }
43374 var fatherBin = {
43375 circles : [],
43376 length : 0,
43377 radius : point.radius / resolution,
43378 x : point.x,
43379 y : point.y
43380 };
43381 for (var k = 0; k < objects.length; k++) {
43382 fatherBin.circles.push(false);
43383 }
43384 var createCircle = function(sx, sy, ball) {
43385 var index = id || ball.search;
43386 var circle = new CircleObject(point.x, point.y, sx, sy, ball.elements, ball.radius, index, ball.weight, fatherBin);
43387 circles[ball.search].push(circle);
43388 fatherBin.circles[index] = circle;
43389 fatherBin.length++;
43390 for (var k = 0; k < ball.elements.length; k++) {
43391 hashMap[ball.search][ball.elements[k].index] = circle;
43392 selectionMap[ball.search][ball.elements[k].index] = false;
43393 }
43394 }
43395 if (balls.length == 1) {
43396 createCircle(0, 0, balls[0]);
43397 } else if (balls.length == 2) {
43398 var r1 = balls[0].radius;
43399 var r2 = balls[1].radius;
43400 createCircle(-1 * r2, 0, balls[0]);
43401 createCircle(r1, 0, balls[1]);
43402 } else if (balls.length == 3) {
43403 balls.sort(orderBalls);
43404 var r1 = balls[0].radius;
43405 var r2 = balls[1].radius;
43406 var r3 = balls[2].radius;
43407 var d = ((2 / 3 * Math.sqrt(3) - 1) / 2) * r2;
43408 var delta1 = point.radius / resolution - r1 - d;
43409 var delta2 = r1 - delta1;
43410 createCircle(-delta1, 0, balls[0]);
43411 createCircle(delta2 + r2 - 3 * d, r2, balls[1]);
43412 createCircle(delta2 + r2 - 3 * d, -1 * r3, balls[2]);
43413 // createCircle(delta2 + r3 - (3 * d * r3 / r2), -1 * r3, balls[2]);
43414 } else if (balls.length == 4) {
43415 balls.sort(orderBalls);
43416 var r1 = balls[0].radius;
43417 var r2 = balls[1].radius;
43418 var r3 = balls[2].radius;
43419 var r4 = balls[3].radius;
43420 var d = (Math.sqrt(2) - 1) * r2;
43421 createCircle(-1 * d - r2, 0, balls[0]);
43422 createCircle(r1 - r2, -1 * d - r4, balls[3]);
43423 createCircle(r1 - r2, d + r3, balls[2]);
43424 createCircle(d + r1, 0, balls[1]);
43425 }
43426 if (fatherBin.length > 1) {
43427 bins.push(fatherBin);
43428 }
43429 }
43430 circleSets.push(circles);
43431 binSets.push(bins);
43432 hashMaps.push(hashMap);
43433 selectionHashs.push(selectionMap);
43434 }
43435 circleSets.reverse();
43436 binSets.reverse();
43437 hashMaps.reverse();
43438 selectionHashs.reverse();
43439 return {
43440 circleSets : circleSets,
43441 binSets : binSets,
43442 hashMaps : hashMaps,
43443 selectionHashs : selectionHashs
43444 };
43445 },
43446
43447 genericBinning : function() {
43448 if (this.options.circlePackings || this.objects.length == 1) {
43449 this.binnings['generic'] = this.genericClustering(this.objects);
43450 } else {
43451 var circleSets = [];
43452 var hashMaps = [];
43453 var selectionHashs = [];
43454 for (var i = 0; i < this.objects.length; i++) {
43455 var sets = this.genericClustering([this.objects[i]], i);
43456 if (i == 0) {
43457 circleSets = sets.circleSets;
43458 hashMaps = sets.hashMaps;
43459 selectionHashs = sets.selectionHashs;
43460 } else {
43461 for (var j = 0; j < circleSets.length; j++) {
43462 circleSets[j] = circleSets[j].concat(sets.circleSets[j]);
43463 hashMaps[j] = hashMaps[j].concat(sets.hashMaps[j]);
43464 selectionHashs[j] = selectionHashs[j].concat(sets.selectionHashs[j]);
43465 }
43466 }
43467 }
43468 this.binnings['generic'] = {
43469 circleSets : circleSets,
43470 hashMaps : hashMaps,
43471 selectionHashs : selectionHashs
43472 };
43473 }
43474 },
43475
43476 getRadius : function(n) {
43477 if (n == 0) {
43478 return 0;
43479 }
43480 if (n == 1) {
43481 return this.minimumRadius;
43482 }
43483 return Math.sqrt((this.minArea + (this.maxArea - this.minArea) / (this.maximumPoints - 1) * (n - 1) ) / Math.PI);
43484 },
43485
43486 getBinRadius : function(n, r_max, N) {
43487 if (n == 0) {
43488 return 0;
43489 }
43490 /*
43491 function log2(x) {
43492 return (Math.log(x)) / (Math.log(2));
43493 }
43494 var r0 = this.options.minimumRadius;
43495 var r;
43496 if ( typeof r_max == 'undefined') {
43497 return r0 + n / Math.sqrt(this.options.maximumPoints);
43498 }
43499 return r0 + (r_max - r0 ) * log2(n) / log2(N);
43500 */
43501 var minArea = Math.PI * this.options.minimumRadius * this.options.minimumRadius;
43502 var maxArea = Math.PI * r_max * r_max;
43503 return Math.sqrt((minArea + (maxArea - minArea) / (N - 1) * (n - 1) ) / Math.PI);
43504 },
43505
43506 shift : function(type, bin, radius, elements) {
43507
43508 var x1 = bin.x, x2 = 0;
43509 var y1 = bin.y, y2 = 0;
43510 for (var i = 0; i < elements.length; i++) {
43511 x2 += elements[i].x / elements.length;
43512 y2 += elements[i].y / elements.length;
43513 }
43514
43515 var sx = 0, sy = 0;
43516
43517 if (type == 'square') {
43518 var dx = Math.abs(x2 - x1);
43519 var dy = Math.abs(y2 - y1);
43520 var m = dy / dx;
43521 var n = y1 - m * x1;
43522 if (dx > dy) {
43523 sx = bin.x - (x1 + bin.r - radius );
43524 sy = bin.y - (m * bin.x + n );
43525 } else {
43526 sy = bin.y - (y1 + bin.r - radius );
43527 sx = bin.x - (bin.y - n) / m;
43528 }
43529 }
43530
43531 return {
43532 x : sx,
43533 y : sy
43534 };
43535
43536 },
43537
43538 binSize : function(elements) {
43539 var size = 0;
43540 for (var i in elements ) {
43541 size += elements[i].weight;
43542 }
43543 return size;
43544 },
43545
43546 setCircleSet : function(id, binData) {
43547 var circleSets = [];
43548 var hashMaps = [];
43549 var selectionHashs = [];
43550 for (var i = 0; i < binData.length; i++) {
43551 var circles = [];
43552 var hashMap = [];
43553 var selectionMap = [];
43554 for (var j = 0; j < this.objects.length; j++) {
43555 circles.push([]);
43556 hashMap.push([]);
43557 selectionMap.push([]);
43558 }
43559 var points = [];
43560 var max = 0;
43561 var radius = 0;
43562 var resolution = this.map.getResolutionForZoom(i);
43563 for (var j = 0; j < binData[i].length; j++) {
43564 for (var k = 0; k < binData[i][j].bin.length; k++) {
43565 var bs = this.binSize(binData[i][j].bin[k]);
43566 if (bs > max) {
43567 max = bs;
43568 radius = binData[i][j].r / resolution;
43569 }
43570 }
43571 }
43572 for (var j = 0; j < binData[i].length; j++) {
43573 var bin = binData[i][j];
43574 for (var k = 0; k < bin.bin.length; k++) {
43575 if (bin.bin[k].length == 0) {
43576 continue;
43577 }
43578 var weight = this.binSize(bin.bin[k]);
43579 var r = this.getBinRadius(weight, radius, max);
43580 var shift = this.shift(id, bin, r * resolution, bin.bin[k], i);
43581 var circle = new CircleObject(bin.x - shift.x, bin.y - shift.y, 0, 0, bin.bin[k], r, k, weight);
43582 circles[k].push(circle);
43583 for (var z = 0; z < bin.bin[k].length; z++) {
43584 hashMap[k][bin.bin[k][z].index] = circle;
43585 selectionMap[k][bin.bin[k][z].index] = false;
43586 }
43587 }
43588 }
43589 circleSets.push(circles);
43590 hashMaps.push(hashMap);
43591 selectionHashs.push(selectionMap);
43592 }
43593 this.binnings[id] = {
43594 circleSets : circleSets,
43595 hashMaps : hashMaps,
43596 selectionHashs : selectionHashs
43597 };
43598 },
43599
43600 squareBinning : function() {
43601
43602 var l = 20037508.34;
43603 var area0 = l * l * 4;
43604 var binCount = this.options.binCount;
43605
43606 var bins = [];
43607 var binData = [];
43608 for (var k = 0; k < this.zoomLevels; k++) {
43609 bins.push([]);
43610 binData.push([]);
43611 }
43612
43613 for (var i = 0; i < this.objects.length; i++) {
43614 for (var j = 0; j < this.objects[i].length; j++) {
43615 var o = this.objects[i][j];
43616 if (!o.isGeospatial) {
43617 continue;
43618 }
43619 var p = new OpenLayers.Geometry.Point(o.getLongitude(this.options.mapIndex), o.getLatitude(this.options.mapIndex), null);
43620 p.transform(this.map.displayProjection, this.map.projection);
43621 o.x = p.x;
43622 o.y = p.y;
43623 for (var k = 0; k < this.zoomLevels; k++) {
43624 var bc = binCount * Math.pow(2, k);
43625 var a = 2 * l / bc;
43626 var binX = Math.floor((p.x + l) / (2 * l) * bc);
43627 var binY = Math.floor((p.y + l) / (2 * l) * bc);
43628 if ( typeof bins[k]['' + binX] == 'undefined') {
43629 bins[k]['' + binX] = [];
43630 }
43631 if ( typeof bins[k][''+binX]['' + binY] == 'undefined') {
43632 bins[k][''+binX]['' + binY] = [];
43633 for (var z = 0; z < this.objects.length; z++) {
43634 bins[k][''+binX]['' + binY].push([]);
43635 }
43636 var x = binX * a + a / 2 - l;
43637 var y = binY * a + a / 2 - l;
43638 binData[k].push({
43639 bin : bins[k][''+binX]['' + binY],
43640 x : x,
43641 y : y,
43642 a : a,
43643 r : a / 2
43644 });
43645 }
43646 bins[k][''+binX][''+binY][i].push(o);
43647 }
43648 }
43649 }
43650
43651 this.setCircleSet('square', binData);
43652
43653 },
43654
43655 triangularBinning : function() {
43656
43657 var l = 20037508.34;
43658 var a0 = this.options.binCount;
43659 var a1 = Math.sqrt(4 * a0 * a0 / Math.sqrt(3));
43660 var binCount = a0 / a1 * a0;
43661
43662 var bins = [];
43663 var binData = [];
43664 for (var k = 0; k < this.zoomLevels; k++) {
43665 bins.push([]);
43666 binData.push([]);
43667 }
43668
43669 for (var i = 0; i < this.objects.length; i++) {
43670 for (var j = 0; j < this.objects[i].length; j++) {
43671 var o = this.objects[i][j];
43672 if (!o.isGeospatial) {
43673 continue;
43674 }
43675 var p = new OpenLayers.Geometry.Point(o.getLongitude(this.options.mapIndex), o.getLatitude(this.options.mapIndex), null);
43676 p.transform(this.map.displayProjection, this.map.projection);
43677 o.x = p.x;
43678 o.y = p.y;
43679 for (var k = 0; k < this.zoomLevels; k++) {
43680 var x_bc = binCount * Math.pow(2, k);
43681 var y_bc = x_bc * x_bc / Math.sqrt(x_bc * x_bc - x_bc * x_bc / 4);
43682 var a = 2 * l / x_bc;
43683 var h = 2 * l / y_bc;
43684 var binY = Math.floor((p.y + l) / (2 * l) * y_bc);
43685 if ( typeof bins[k]['' + binY] == 'undefined') {
43686 bins[k]['' + binY] = [];
43687 }
43688 var triangleIndex;
43689 var partitionsX = x_bc * 2;
43690 var partition = Math.floor((p.x + l) / (2 * l) * partitionsX);
43691 var xMax = a / 2;
43692 var yMax = h;
43693 var x = p.x + l - partition * a / 2;
43694 var y = p.y + l - binY * h;
43695 if (binY % 2 == 0 && partition % 2 == 1 || binY % 2 == 1 && partition % 2 == 0) {
43696 if (y + yMax / xMax * x < yMax) {
43697 triangleIndex = partition;
43698 } else {
43699 triangleIndex = partition + 1;
43700 }
43701 } else {
43702 if (y > yMax / xMax * x) {
43703 triangleIndex = partition;
43704 } else {
43705 triangleIndex = partition + 1;
43706 }
43707 }
43708 if ( typeof bins[k][''+binY]['' + triangleIndex] == 'undefined') {
43709 bins[k][''+binY]['' + triangleIndex] = [];
43710 for (var z = 0; z < this.objects.length; z++) {
43711 bins[k][''+binY]['' + triangleIndex].push([]);
43712 }
43713 var r = Math.sqrt(3) / 6 * a;
43714 var x = (triangleIndex - 1) * a / 2 + a / 2 - l;
43715 var y;
43716 if (binY % 2 == 0 && triangleIndex % 2 == 0 || binY % 2 == 1 && triangleIndex % 2 == 1) {
43717 y = binY * h + h - r - l;
43718 } else {
43719 y = binY * h + r - l;
43720 }
43721 binData[k].push({
43722 bin : bins[k][''+binY]['' + triangleIndex],
43723 x : x,
43724 y : y,
43725 a : a,
43726 r : r
43727 });
43728 }
43729 bins[k][''+binY][''+triangleIndex][i].push(o);
43730 }
43731 }
43732 }
43733
43734 this.setCircleSet('triangular', binData);
43735
43736 },
43737
43738 hexagonalBinning : function() {
43739
43740 var l = 20037508.34;
43741 var a0 = this.options.binCount;
43742 var a2 = Math.sqrt(4 * a0 * a0 / Math.sqrt(3)) / Math.sqrt(6);
43743 var binCount = a0 / a2 * a0;
43744
43745 var bins = [];
43746 var binData = [];
43747 for (var k = 0; k < this.zoomLevels; k++) {
43748 bins.push([]);
43749 binData.push([]);
43750 }
43751
43752 for (var i = 0; i < this.objects.length; i++) {
43753 for (var j = 0; j < this.objects[i].length; j++) {
43754 var o = this.objects[i][j];
43755 if (!o.isGeospatial) {
43756 continue;
43757 }
43758 var p = new OpenLayers.Geometry.Point(o.getLongitude(this.options.mapIndex), o.getLatitude(this.options.mapIndex), null);
43759 p.transform(this.map.displayProjection, this.map.projection);
43760 o.x = p.x;
43761 o.y = p.y;
43762 for (var k = 0; k < this.zoomLevels; k++) {
43763 var x_bc = binCount * Math.pow(2, k);
43764 var y_bc = x_bc * x_bc / Math.sqrt(x_bc * x_bc - x_bc * x_bc / 4);
43765 var a = 2 * l / x_bc;
43766 var h = 2 * l / y_bc;
43767 var binY = Math.floor((p.y + l) / (2 * l) * y_bc);
43768 if ( typeof bins[k]['' + binY] == 'undefined') {
43769 bins[k]['' + binY] = [];
43770 }
43771 var triangleIndex;
43772 var partitionsX = x_bc * 2;
43773 var partition = Math.floor((p.x + l) / (2 * l) * partitionsX);
43774 var xMax = a / 2;
43775 var yMax = h;
43776 var x = p.x + l - partition * a / 2;
43777 var y = p.y + l - binY * h;
43778 if (binY % 2 == 0 && partition % 2 == 1 || binY % 2 == 1 && partition % 2 == 0) {
43779 if (y + yMax / xMax * x < yMax) {
43780 triangleIndex = partition;
43781 } else {
43782 triangleIndex = partition + 1;
43783 }
43784 } else {
43785 if (y > yMax / xMax * x) {
43786 triangleIndex = partition;
43787 } else {
43788 triangleIndex = partition + 1;
43789 }
43790 }
43791 if ( typeof bins[k][''+binY]['' + triangleIndex] == 'undefined') {
43792 bins[k][''+binY]['' + triangleIndex] = [];
43793 for (var z = 0; z < this.objects.length; z++) {
43794 bins[k][''+binY]['' + triangleIndex].push([]);
43795 }
43796 var r = Math.sqrt(3) / 6 * a;
43797 var x = (triangleIndex - 1) * a / 2 + a / 2 - l;
43798 var y;
43799 if (binY % 2 == 0 && triangleIndex % 2 == 0 || binY % 2 == 1 && triangleIndex % 2 == 1) {
43800 y = binY * h + h - r - l;
43801 } else {
43802 y = binY * h + r - l;
43803 }
43804 binData[k].push({
43805 bin : bins[k][''+binY]['' + triangleIndex],
43806 x : x,
43807 y : y,
43808 a : a,
43809 r : r,
43810 h : h,
43811 binX : triangleIndex,
43812 binY : binY
43813 });
43814 }
43815 bins[k][''+binY][''+triangleIndex][i].push(o);
43816 }
43817 }
43818 }
43819
43820 var hexaBins = [];
43821 var hexaBinData = [];
43822 for (var k = 0; k < this.zoomLevels; k++) {
43823 hexaBins.push([]);
43824 hexaBinData.push([]);
43825 }
43826
43827 for (var i = 0; i < binData.length; i++) {
43828 for (var j = 0; j < binData[i].length; j++) {
43829 var bin = binData[i][j];
43830 var binY = Math.floor(bin.binY / 2);
43831 var binX = Math.floor(bin.binX / 3);
43832 var x, y;
43833 var a = bin.a;
43834 var h = bin.h;
43835 if (bin.binX % 6 < 3) {
43836 if ( typeof hexaBins[i]['' + binY] == 'undefined') {
43837 hexaBins[i]['' + binY] = [];
43838 }
43839 y = binY * 2 * bin.h + bin.h - l;
43840 x = binX * 1.5 * bin.a + a / 2 - l;
43841 } else {
43842 if (bin.binY % 2 == 1) {
43843 binY++;
43844 }
43845 if ( typeof hexaBins[i]['' + binY] == 'undefined') {
43846 hexaBins[i]['' + binY] = [];
43847 }
43848 y = binY * 2 * bin.h - l;
43849 x = binX * 1.5 * bin.a + a / 2 - l;
43850 }
43851 if ( typeof hexaBins[i][''+binY]['' + binX] == 'undefined') {
43852 hexaBins[i][''+binY]['' + binX] = [];
43853 for (var z = 0; z < this.objects.length; z++) {
43854 hexaBins[i][''+binY]['' + binX].push([]);
43855 }
43856 hexaBinData[i].push({
43857 bin : hexaBins[i][''+binY]['' + binX],
43858 x : x,
43859 y : y,
43860 a : bin.a,
43861 r : bin.h
43862 });
43863 }
43864 for (var k = 0; k < bin.bin.length; k++) {
43865 for (var m = 0; m < bin.bin[k].length; m++) {
43866 hexaBins[i][''+binY][''+binX][k].push(bin.bin[k][m]);
43867 }
43868 }
43869 }
43870 }
43871
43872 this.setCircleSet('hexagonal', hexaBinData);
43873
43874 }
43875 }
43876
43877 /*
43878 * MapDataSource.js
43879 *
43880 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
43881 *
43882 * This library is free software; you can redistribute it and/or
43883 * modify it under the terms of the GNU Lesser General Public
43884 * License as published by the Free Software Foundation; either
43885 * version 3 of the License, or (at your option) any later version.
43886 *
43887 * This library is distributed in the hope that it will be useful,
43888 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43889 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
43890 * Lesser General Public License for more details.
43891 *
43892 * You should have received a copy of the GNU Lesser General Public
43893 * License along with this library; if not, write to the Free Software
43894 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
43895 * MA 02110-1301 USA
43896 */
43897
43898 /**
43899 * @class MapDataSource
43900 * implementation for aggregation of map items
43901 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
43902 * @release 1.0
43903 * @release date: 2012-07-27
43904 * @version date: 2012-07-27
43905 *
43906 * @param {OpenLayers.Map} olMap openlayers map object of the map widget
43907 * @param {JSON} options map configuration
43908 */
43909 function MapDataSource(olMap, options) {
43910
43911 this.olMap = olMap;
43912 this.circleSets = [];
43913 this.binning = new Binning(olMap, options);
43914
43915 };
43916
43917 MapDataSource.prototype = {
43918
43919 /**
43920 * initializes the MapDataSource
43921 * @param {MapObject[][]} mapObjects an array of map objects of different sets
43922 */
43923 initialize : function(mapObjects) {
43924
43925 if (mapObjects != this.mapObjects) {
43926 this.binning.reset();
43927 this.binning.setObjects(mapObjects);
43928 }
43929 this.mapObjects = mapObjects;
43930
43931 var set = this.binning.getSet();
43932 this.circleSets = set.circleSets;
43933 this.binSets = set.binSets;
43934 this.hashMapping = set.hashMaps;
43935
43936 },
43937
43938 getObjectsByZoom : function() {
43939 var zoom = Math.floor(this.olMap.getZoom());
43940 if (this.circleSets.length < zoom) {
43941 return null;
43942 }
43943 return this.circleSets[zoom];
43944 },
43945
43946 getAllObjects : function() {
43947 if (this.circleSets.length == 0) {
43948 return null;
43949 }
43950 return this.circleSets;
43951 },
43952
43953 getAllBins : function() {
43954 if (this.binSets.length == 0) {
43955 return null;
43956 }
43957 return this.binSets;
43958 },
43959
43960 clearOverlay : function() {
43961 var zoom = Math.floor(this.olMap.getZoom());
43962 var circles = this.circleSets[zoom];
43963 for (var i in circles ) {
43964 for (var j in circles[i] ) {
43965 circles[i][j].reset();
43966 }
43967 }
43968 },
43969
43970 setOverlay : function(mapObjects) {
43971 var zoom = Math.floor(this.olMap.getZoom());
43972 for (var j in mapObjects ) {
43973 for (var k in mapObjects[j] ) {
43974 var o = mapObjects[j][k];
43975 if (o.isGeospatial) {
43976 this.hashMapping[zoom][j][o.index].overlayElements.push(o);
43977 this.hashMapping[zoom][j][o.index].overlay += o.weight;
43978 }
43979 }
43980 }
43981 },
43982
43983 size : function() {
43984 if (this.circleSets.length == 0) {
43985 return 0;
43986 }
43987 return this.circleSets[0].length;
43988 },
43989
43990 getCircle : function(index, id) {
43991 var zoom = Math.floor(this.olMap.getZoom());
43992 return this.hashMapping[zoom][index][id];
43993 }
43994 };
43995 /*
43996 * Clustering.js
43997 *
43998 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
43999 *
44000 * This library is free software; you can redistribute it and/or
44001 * modify it under the terms of the GNU Lesser General Public
44002 * License as published by the Free Software Foundation; either
44003 * version 3 of the License, or (at your option) any later version.
44004 *
44005 * This library is distributed in the hope that it will be useful,
44006 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44007 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44008 * Lesser General Public License for more details.
44009 *
44010 * You should have received a copy of the GNU Lesser General Public
44011 * License along with this library; if not, write to the Free Software
44012 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
44013 * MA 02110-1301 USA
44014 */
44015
44016 /**
44017 * @class Vertex, Edge, Triangle, Clustering, BinaryHeap
44018 * Dynamic Delaunay clustering algorithm (see GeoTemCo paper)
44019 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
44020 * @release 1.0
44021 * @release date: 2012-07-27
44022 * @version date: 2012-07-27
44023 */
44024
44025 function Vertex(x, y, categories, binning) {
44026 this.x = x;
44027 this.y = y;
44028 this.radius
44029 this.size = 0;
44030 this.elements = [];
44031 this.radii = [];
44032 this.weights = [];
44033 this.legal = true;
44034 this.binning = binning;
44035 if (categories != undefined) {
44036 for (var i = 0; i < categories; i++) {
44037 this.elements.push([]);
44038 this.weights.push(0);
44039 }
44040 }
44041 }
44042
44043 Vertex.prototype.merge = function(v0, v1) {
44044 for (var i = 0; i < v0.elements.length; i++) {
44045 this.elements[i] = v0.elements[i].concat(v1.elements[i]);
44046 this.weights[i] = v0.weights[i] + v1.weights[i];
44047 this.size += this.weights[i];
44048 }
44049 }
44050
44051 Vertex.prototype.CalculateRadius = function(resolution) {
44052 this.radii = [];
44053 for (i in this.elements ) {
44054 this.radii.push(this.binning.getRadius(this.weights[i]));
44055 }
44056 if (this.radii.length == 1) {
44057 this.radius = this.radii[0] * resolution;
44058 } else {
44059 var count = 0;
44060 var max1 = 0;
44061 var max2 = 0;
44062 for (i in this.radii ) {
44063 if (this.radii[i] != 0) {
44064 count++;
44065 }
44066 if (this.radii[i] > max1) {
44067 if (max1 > max2) {
44068 max2 = max1;
44069 }
44070 max1 = this.radii[i];
44071 } else if (this.radii[i] > max2) {
44072 max2 = this.radii[i];
44073 }
44074 }
44075 if (count == 1) {
44076 this.radius = max1 * resolution;
44077 } else if (count == 2) {
44078 this.radius = (max1 + max2) * resolution;
44079 } else if (count == 3) {
44080 var d = (2 / 3 * Math.sqrt(3) - 1) * max1;
44081 this.radius = (d + max1 + max2) * resolution;
44082 } else if (count == 4) {
44083 var d = (Math.sqrt(2) - 1) * max2;
44084 this.radius = (d + max1 + max2) * resolution;
44085 }
44086 }
44087 }
44088
44089 Vertex.prototype.addElement = function(e, weight, index) {
44090 this.elements[index].push(e);
44091 this.size += weight;
44092 this.weights[index] += weight;
44093 }
44094 function Edge(v0, v1) {
44095 this.v0 = v0;
44096 this.v1 = v1;
44097 this.leftFace
44098 this.rightFace
44099 this.legal = true;
44100 this.setLength();
44101 }
44102
44103 Edge.prototype.setLength = function() {
44104 var dx = this.v0.x - this.v1.x;
44105 var dy = this.v0.y - this.v1.y;
44106 this.length = Math.sqrt(dx * dx + dy * dy);
44107 }
44108
44109 Edge.prototype.contains = function(v) {
44110 if (this.v0 == v || this.v1 == v) {
44111 return true;
44112 }
44113 return false;
44114 }
44115
44116 Edge.prototype.replaceFace = function(f_old, f_new) {
44117 if (this.leftFace == f_old) {
44118 this.leftFace = f_new;
44119 } else if (this.rightFace == f_old) {
44120 this.rightFace = f_new;
44121 }
44122 }
44123
44124 Edge.prototype.setFace = function(f) {
44125 if (f.leftOf(this)) {
44126 this.leftFace = f;
44127 } else {
44128 this.rightFace = f;
44129 }
44130 }
44131
44132 Edge.prototype.setFaces = function(f1, f2) {
44133 if (f1.leftOf(this)) {
44134 this.leftFace = f1;
44135 this.rightFace = f2;
44136 } else {
44137 this.leftFace = f2;
44138 this.rightFace = f1;
44139 }
44140 }
44141
44142 Edge.prototype.removeFace = function(f) {
44143 if (this.leftFace == f) {
44144 this.leftFace = null;
44145 } else {
44146 this.rightFace = null;
44147 }
44148 }
44149
44150 Edge.prototype.equals = function(e) {
44151 if (this.v0 == e.v0 && this.v1 == e.v1 || this.v0 == e.v1 && this.v1 == e.v0) {
44152 return true;
44153 }
44154 return false;
44155 }
44156 function Triangle(edges) {
44157 this.edges = edges;
44158 this.setVertices();
44159 this.descendants = [];
44160 }
44161
44162 Triangle.prototype.getTriple = function(e) {
44163 var i = arrayIndex(this.edges, e);
44164 return {
44165 e_s : this.edges[(i + 1) % 3],
44166 e_p : this.edges[(i + 2) % 3],
44167 u : this.vertices[(i + 2) % 3]
44168 };
44169 }
44170
44171 Triangle.prototype.leftOf = function(e) {
44172 var i = arrayIndex(this.edges, e);
44173 if (this.vertices[i].y != this.vertices[(i + 1) % 3].y) {
44174 return this.vertices[i].y > this.vertices[(i + 1) % 3].y;
44175 }
44176 return this.vertices[i].y > this.vertices[(i + 2) % 3].y;
44177 }
44178
44179 Triangle.prototype.getNext = function(v) {
44180 var i = arrayIndex(this.vertices, v);
44181 return this.vertices[(i + 1) % 3];
44182 }
44183
44184 Triangle.prototype.oppositeEdge = function(v) {
44185 var i = arrayIndex(this.vertices, v);
44186 return this.edges[(i + 1) % 3];
44187 }
44188
44189 Triangle.prototype.contains = function(v) {
44190 return arrayIndex(this.vertices, v) != -1;
44191 }
44192
44193 Triangle.prototype.replace = function(e_old, e_new) {
44194 this.edges[arrayIndex(this.edges, e_old)] = e_new;
44195 }
44196
44197 Triangle.prototype.setVertices = function() {
44198 if (this.edges[1].v0 == this.edges[0].v0 || this.edges[1].v1 == this.edges[0].v0) {
44199 this.vertices = [this.edges[0].v1, this.edges[0].v0];
44200 } else {
44201 this.vertices = [this.edges[0].v0, this.edges[0].v1];
44202 }
44203 if (this.edges[2].v0 == this.vertices[0]) {
44204 this.vertices.push(this.edges[2].v1);
44205 } else {
44206 this.vertices.push(this.edges[2].v0);
44207 }
44208 }
44209
44210 Triangle.prototype.replaceBy = function(triangles) {
44211 this.descendants = triangles;
44212 this.edges[0].replaceFace(this, triangles[0]);
44213 this.edges[1].replaceFace(this, triangles[1]);
44214 this.edges[2].replaceFace(this, triangles[2]);
44215 }
44216
44217 Triangle.prototype.CalcCircumcircle = function() {
44218 var v0 = this.vertices[0];
44219 var v1 = this.vertices[1];
44220 var v2 = this.vertices[2];
44221 var A = v1.x - v0.x;
44222 var B = v1.y - v0.y;
44223 var C = v2.x - v0.x;
44224 var D = v2.y - v0.y;
44225 var E = A * (v0.x + v1.x) + B * (v0.y + v1.y);
44226 var F = C * (v0.x + v2.x) + D * (v0.y + v2.y);
44227 var G = 2.0 * (A * (v2.y - v1.y) - B * (v2.x - v1.x));
44228 var cx = (D * E - B * F) / G;
44229 var cy = (A * F - C * E) / G;
44230 this.center = new Vertex(cx, cy);
44231 var dx = this.center.x - v0.x;
44232 var dy = this.center.y - v0.y;
44233 this.radius_squared = dx * dx + dy * dy;
44234 };
44235
44236 Triangle.prototype.inCircumcircle = function(v) {
44237 if (this.radius_squared == undefined) {
44238 this.CalcCircumcircle();
44239 }
44240 var dx = this.center.x - v.x;
44241 var dy = this.center.y - v.y;
44242 var dist_squared = dx * dx + dy * dy;
44243 return (dist_squared <= this.radius_squared );
44244 };
44245
44246 Triangle.prototype.interior = function(v) {
44247 var v0 = this.vertices[0];
44248 var v1 = this.vertices[1];
44249 var v2 = this.vertices[2];
44250 var dotAB = (v.x - v0.x ) * (v0.y - v1.y ) + (v.y - v0.y ) * (v1.x - v0.x );
44251 var dotBC = (v.x - v1.x ) * (v1.y - v2.y ) + (v.y - v1.y ) * (v2.x - v1.x );
44252 var dotCA = (v.x - v2.x ) * (v2.y - v0.y ) + (v.y - v2.y ) * (v0.x - v2.x );
44253 if (dotAB > 0 || dotBC > 0 || dotCA > 0) {
44254 return null;
44255 } else if (dotAB < 0 && dotBC < 0 && dotCA < 0) {
44256 return this;
44257 } else if (dotAB == 0) {
44258 if (dotBC == 0) {
44259 return this.vertices[1];
44260 } else if (dotCA == 0) {
44261 return this.vertices[0];
44262 }
44263 return this.edges[0];
44264 } else if (dotBC == 0) {
44265 if (dotCA == 0) {
44266 return this.vertices[2];
44267 }
44268 return this.edges[1];
44269 } else if (dotCA == 0) {
44270 return this.edges[2];
44271 }
44272 };
44273
44274 function Clustering(xMin, yMin, xMax, yMax) {
44275 this.triangles = [];
44276 this.newTriangles = [];
44277 this.bbox = {
44278 x1 : xMin,
44279 y1 : yMin,
44280 x2 : xMax,
44281 y2 : yMax
44282 };
44283 this.CreateBoundingTriangle();
44284 this.edges = [];
44285 this.vertices = [];
44286 this.legalizes = 0;
44287 this.collapses = 0;
44288 }
44289
44290 Clustering.prototype.locate = function(v) {
44291 if (this.boundingTriangle.descendants.length == 0) {
44292 return this.boundingTriangle;
44293 }
44294 var triangles = this.boundingTriangle.descendants;
44295 while (true) {
44296 for (var i = 0; i < triangles.length; i++) {
44297 var simplex = triangles[i].interior(v);
44298 if (simplex == null) {
44299 continue;
44300 }
44301 if ( simplex instanceof Vertex || this.isLeaf(triangles[i])) {
44302 return simplex;
44303 }
44304 triangles = triangles[i].descendants;
44305 break;
44306 }
44307 }
44308 }
44309
44310 Clustering.prototype.legalize = function(v, e, t0_old) {
44311 if (!e.v0.legal && !e.v1.legal) {
44312 return;
44313 }
44314 this.legalizes++;
44315 var flip = false;
44316 var t1_old, tr1;
44317 if (e.leftFace == t0_old && e.rightFace.inCircumcircle(v)) {
44318 flip = true;
44319 t1_old = e.rightFace;
44320 } else if (e.rightFace == t0_old && e.leftFace.inCircumcircle(v)) {
44321 flip = true;
44322 t1_old = e.leftFace;
44323 }
44324 if (flip) {
44325 var tr0 = t0_old.getTriple(e);
44326 var tr1 = t1_old.getTriple(e);
44327 var e_flip = new Edge(tr0.u, tr1.u);
44328 var poly = [];
44329 poly.push(e.v0);
44330 poly.push(e_flip.v0);
44331 poly.push(e.v1);
44332 poly.push(e_flip.v1);
44333 if (!this.JordanTest(poly, e_flip)) {
44334 return;
44335 }
44336 e.legal = false;
44337 this.edges.push(e_flip);
44338 var t0_new = new Triangle([e_flip, tr0.e_p, tr1.e_s]);
44339 var t1_new = new Triangle([e_flip, tr1.e_p, tr0.e_s]);
44340 e_flip.setFaces(t0_new, t1_new);
44341 tr0.e_p.replaceFace(t0_old, t0_new);
44342 tr1.e_s.replaceFace(t1_old, t0_new);
44343 tr1.e_p.replaceFace(t1_old, t1_new);
44344 tr0.e_s.replaceFace(t0_old, t1_new);
44345 t0_old.descendants = [t0_new, t1_new];
44346 t1_old.descendants = [t0_new, t1_new];
44347 this.legalize(v, t0_new.edges[2], t0_new);
44348 this.legalize(v, t1_new.edges[1], t1_new);
44349 }
44350 }
44351
44352 Clustering.prototype.add = function(v) {
44353 this.addVertex(v, this.locate(v));
44354 }
44355
44356 Clustering.prototype.addVertex = function(v, simplex) {
44357 if ( simplex instanceof Vertex) {
44358 simplex.merge(simplex, v);
44359 } else if ( simplex instanceof Edge) {
44360 this.vertices.push(v);
44361 simplex.legal = false;
44362 var tr0 = simplex.leftFace.getTriple(simplex);
44363 var tr1 = simplex.rightFace.getTriple(simplex);
44364 var e0 = new Edge(v, tr0.u);
44365 var e1 = new Edge(v, simplex.leftFace.getNext(tr0.u));
44366 var e2 = new Edge(v, tr1.u);
44367 var e3 = new Edge(v, simplex.rightFace.getNext(tr1.u));
44368 var t0 = new Triangle([e0, tr0.e_p, e1]);
44369 var t1 = new Triangle([e1, tr1.e_s, e2]);
44370 var t2 = new Triangle([e2, tr1.e_p, e3]);
44371 var t3 = new Triangle([e3, tr0.e_s, e0]);
44372 simplex.leftFace.descendants = [t0, t3];
44373 simplex.rightFace.descendants = [t1, t2];
44374 this.edges.push(e0);
44375 this.edges.push(e1);
44376 this.edges.push(e2);
44377 this.edges.push(e3);
44378 e0.setFaces(t0, t3);
44379 e1.setFaces(t0, t1);
44380 e2.setFaces(t1, t2);
44381 e3.setFaces(t2, t3);
44382 tr0.e_p.replaceFace(simplex.leftFace, t0);
44383 tr1.e_s.replaceFace(simplex.rightFace, t1);
44384 tr1.e_p.replaceFace(simplex.rightFace, t2);
44385 tr0.e_s.replaceFace(simplex.leftFace, t3);
44386 this.legalize(v, tr0.e_p, t0);
44387 this.legalize(v, tr1.e_s, t1);
44388 this.legalize(v, tr1.e_p, t2);
44389 this.legalize(v, tr0.e_s, t3);
44390 } else {
44391 this.vertices.push(v);
44392 var e_i = new Edge(simplex.vertices[0], v);
44393 var e_j = new Edge(simplex.vertices[1], v);
44394 var e_k = new Edge(simplex.vertices[2], v);
44395 this.edges.push(e_i);
44396 this.edges.push(e_j);
44397 this.edges.push(e_k);
44398 var t0 = new Triangle([e_i, simplex.edges[0], e_j]);
44399 var t1 = new Triangle([e_j, simplex.edges[1], e_k]);
44400 var t2 = new Triangle([e_k, simplex.edges[2], e_i]);
44401 e_i.setFaces(t0, t2);
44402 e_j.setFaces(t0, t1);
44403 e_k.setFaces(t1, t2);
44404 simplex.replaceBy([t0, t1, t2]);
44405 this.legalize(v, simplex.edges[0], t0);
44406 this.legalize(v, simplex.edges[1], t1);
44407 this.legalize(v, simplex.edges[2], t2);
44408 }
44409 }
44410
44411 Clustering.prototype.isLeaf = function(t) {
44412 return t.descendants.length == 0;
44413 }
44414
44415 Clustering.prototype.CreateBoundingTriangle = function() {
44416 var dx = (this.bbox.x2 - this.bbox.x1 ) * 10;
44417 var dy = (this.bbox.y2 - this.bbox.y1 ) * 10;
44418 var v0 = new Vertex(this.bbox.x1 - dx, this.bbox.y1 - dy * 3);
44419 var v1 = new Vertex(this.bbox.x2 + dx * 3, this.bbox.y2 + dy);
44420 var v2 = new Vertex(this.bbox.x1 - dx, this.bbox.y2 + dy);
44421 var e0 = new Edge(v1, v0);
44422 var e1 = new Edge(v0, v2);
44423 var e2 = new Edge(v2, v1);
44424 v0.legal = false;
44425 v1.legal = false;
44426 v2.legal = false;
44427 this.boundingTriangle = new Triangle([e0, e1, e2]);
44428 var inf = new Triangle([e0, e1, e2]);
44429 e0.setFaces(this.boundingTriangle, inf);
44430 e1.setFaces(this.boundingTriangle, inf);
44431 e2.setFaces(this.boundingTriangle, inf);
44432 }
44433
44434 Clustering.prototype.mergeVertices = function(e) {
44435 this.collapses++;
44436 var s0 = e.v0.size;
44437 var s1 = e.v1.size;
44438 var x = (e.v0.x * s0 + e.v1.x * s1 ) / (s0 + s1 );
44439 var y = (e.v0.y * s0 + e.v1.y * s1 ) / (s0 + s1 );
44440 var v = new Vertex(x, y, e.v0.elements.length, e.v0.binning);
44441 v.merge(e.v0, e.v1);
44442
44443 e.v0.legal = false;
44444 e.v1.legal = false;
44445
44446 var hole = [];
44447 var oldFacets = [];
44448 e.legal = false;
44449
44450 var vertices = [];
44451 var traverse = function(eLeft, eRight, triangle) {
44452 eLeft.legal = false;
44453 do {
44454 var triple;
44455 if (eLeft.leftFace == triangle) {
44456 triple = eLeft.rightFace.getTriple(eLeft);
44457 oldFacets.push(eLeft.rightFace);
44458 triple.e_s.removeFace(eLeft.rightFace);
44459 triangle = eLeft.rightFace;
44460 } else {
44461 triple = eLeft.leftFace.getTriple(eLeft);
44462 oldFacets.push(eLeft.leftFace);
44463 triple.e_s.removeFace(eLeft.leftFace);
44464 triangle = eLeft.leftFace;
44465 }
44466 if (arrayIndex(hole, triple.e_s) == -1) {
44467 hole.push(triple.e_s);
44468 }
44469 vertices.push(triple.u);
44470 eLeft = triple.e_p;
44471 eLeft.legal = false;
44472 } while( eLeft != eRight );
44473 }
44474 var tr0 = e.leftFace.getTriple(e);
44475 var tr1 = e.rightFace.getTriple(e);
44476 oldFacets.push(e.leftFace);
44477 oldFacets.push(e.rightFace);
44478 traverse(tr0.e_p, tr1.e_s, e.leftFace);
44479 traverse(tr1.e_p, tr0.e_s, e.rightFace);
44480
44481 var hd = new Clustering(this.bbox.x1 - 10, this.bbox.y1 - 10, this.bbox.x2 + 10, this.bbox.y2 + 10);
44482 var hull = [];
44483 for (var i in hole ) {
44484 if (!(hole[i].leftFace == null && hole[i].rightFace == null)) {
44485 hull.push(hole[i].v0);
44486 hull.push(hole[i].v1);
44487 }
44488 }
44489 var hullVertices = [];
44490 var distinct = [];
44491 for (var i in vertices ) {
44492 if (arrayIndex(distinct, vertices[i]) == -1) {
44493 hd.add(vertices[i]);
44494 distinct.push(vertices[i]);
44495 }
44496 if (arrayIndex(hull, vertices[i]) != -1) {
44497 hullVertices.push(vertices[i]);
44498 }
44499 }
44500
44501 var newFacets = [];
44502 var isBoundary = function(e) {
44503 for (var i = 0; i < hole.length; i++) {
44504 if (hole[i].equals(e)) {
44505 return i;
44506 }
44507 }
44508 return -1;
44509 }
44510 var holeEdges = new Array(hole.length);
44511 var nonHoleEdges = [];
44512
44513 for (var i = 0; i < hd.edges.length; i++) {
44514 var e = hd.edges[i];
44515 var b = isBoundary(e);
44516 if (b != -1) {
44517 if (!e.legal) {
44518 var t1 = e.leftFace.getTriple(e);
44519 var t2 = e.rightFace.getTriple(e);
44520 var edge = new Edge(t1.u, t2.u);
44521 for (var j = 0; j < hd.edges.length; j++) {
44522 if (hd.edges[j].equals(edge) && hd.edges[j].legal) {
44523 hd.edges[j].legal = false;
44524 break;
44525 }
44526 }
44527 t1.e_p.setFace(e.leftFace);
44528 t1.e_s.setFace(e.leftFace);
44529 t2.e_p.setFace(e.rightFace);
44530 t2.e_s.setFace(e.rightFace);
44531
44532 e.legal = true;
44533 }
44534 holeEdges[b] = e;
44535 } else {
44536 nonHoleEdges.push(e);
44537 }
44538 }
44539
44540 for (var i = 0; i < holeEdges.length; i++) {
44541 var e = holeEdges[i];
44542 if (hole[i].leftFace == null) {
44543 hole[i].leftFace = e.leftFace;
44544 hole[i].leftFace.replace(e, hole[i]);
44545 if (arrayIndex(newFacets, hole[i].leftFace) == -1) {
44546 newFacets.push(hole[i].leftFace);
44547 }
44548 }
44549 if (hole[i].rightFace == null) {
44550 hole[i].rightFace = e.rightFace;
44551 hole[i].rightFace.replace(e, hole[i]);
44552 if (arrayIndex(newFacets, hole[i].rightFace) == -1) {
44553 newFacets.push(hole[i].rightFace);
44554 }
44555 }
44556 }
44557
44558 for (var i = 0; i < nonHoleEdges.length; i++) {
44559 var e = nonHoleEdges[i];
44560 if (!e.legal) {
44561 continue;
44562 }
44563 if (this.JordanTest(hullVertices, e)) {
44564 this.edges.push(e);
44565 if (arrayIndex(newFacets, e.rightFace) == -1) {
44566 newFacets.push(e.rightFace);
44567 }
44568 if (arrayIndex(newFacets, e.leftFace) == -1) {
44569 newFacets.push(e.leftFace);
44570 }
44571 }
44572 }
44573
44574 for (var i in oldFacets ) {
44575 oldFacets[i].descendants = newFacets;
44576 }
44577
44578 for (var i = 0; i < newFacets.length; i++) {
44579 var simplex = newFacets[i].interior(v);
44580 if (simplex == null) {
44581 continue;
44582 } else {
44583 this.addVertex(v, simplex);
44584 break;
44585 }
44586 }
44587
44588 return v;
44589
44590 }
44591
44592 Clustering.prototype.JordanTest = function(pol, e) {
44593 var p = new Vertex((e.v0.x + e.v1.x) * 0.5, (e.v0.y + e.v1.y) * 0.5);
44594 var inside = false;
44595 var i, j = pol.length - 1;
44596 for ( i = 0; i < pol.length; j = i++) {
44597 var p1 = pol[i];
44598 var p2 = pol[j];
44599 if ((((p1.y <= p.y) && (p.y < p2.y)) || ((p2.y <= p.y) && (p.y < p1.y))) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x))
44600 inside = !inside;
44601 }
44602 return inside;
44603 }
44604
44605 Clustering.prototype.mergeForResolution = function(resolution, circleGap, circleOverlap) {
44606 this.deleteEdges = new BinaryHeap(function(e) {
44607 return e.weight;
44608 });
44609 this.weightEdges(resolution, circleGap, circleOverlap);
44610 var index = 0;
44611 while (this.deleteEdges.size() > 0) {
44612 var e = this.deleteEdges.pop();
44613 if (e.legal) {
44614 var l = this.edges.length;
44615 var newVertex = this.mergeVertices(e);
44616 newVertex.CalculateRadius(resolution);
44617 for (var k = l; k < this.edges.length; k++) {
44618 var eNew = this.edges[k];
44619 if (eNew.legal) {
44620 if( circleGap != 0 ){
44621 eNew.weight = eNew.length / (eNew.v0.radius + eNew.v1.radius + circleGap * resolution );
44622 }
44623 else if( circleOverlap.overlap == 0 ){
44624 eNew.weight = eNew.length / (eNew.v0.radius + eNew.v1.radius);
44625 }
44626 else {
44627 var r1 = eNew.v0.radius;
44628 var r2 = eNew.v1.radius;
44629 var r = eNew.length;
44630 if( r < r1 + r2 ){
44631 if( circleOverlap.type == 'diameter' ){
44632 var ol1 = (r2-(r-r1)) / r1 / 2;
44633 var ol2 = (r1-(r-r2)) / r2 / 2;
44634 var ol = Math.max(ol1,ol2);
44635 eNew.weight = circleOverlap.overlap / ol;
44636 }
44637 if( circleOverlap.type == 'area' ){
44638 if( !(r+r1 < r2 || r+r2 < r1) ){
44639 var A = r2*r2*Math.acos((r*r+r2*r2-r1*r1)/(2*r*r2))+r1*r1*Math.acos((r*r+r1*r1-r2*r2)/(2*r*r1))-1/2*Math.sqrt((-r+r1+r2)*(r-r1+r2)*(r+r1-r2)*(r+r1+r2));
44640 var ol1 = A / (Math.PI*r1*r1);
44641 var ol2 = A / (Math.PI*r2*r2);
44642 var ol = Math.max(ol1,ol2);
44643 eNew.weight = circleOverlap.overlap / ol;
44644 }
44645 else {
44646 eNew.weight = 0;
44647 }
44648 }
44649 }
44650 }
44651 if (eNew.weight < 1) {
44652 this.deleteEdges.push(eNew);
44653 }
44654 }
44655 }
44656 }
44657 }
44658 }
44659
44660 Clustering.prototype.weightEdges = function(resolution, circleGap, circleOverlap) {
44661 for (var i = 0; i < this.vertices.length; i++) {
44662 if (this.vertices[i].legal) {
44663 this.vertices[i].CalculateRadius(resolution);
44664 }
44665 }
44666 var newEdges = [];
44667 for (var i = 0; i < this.edges.length; i++) {
44668 var e = this.edges[i];
44669 if (e.legal) {
44670 if (!e.v0.legal || !e.v1.legal) {
44671 e.weight = 1;
44672 } else {
44673 if( circleGap != 0 ){
44674 e.weight = e.length / (e.v0.radius + e.v1.radius + circleGap * resolution );
44675 }
44676 else if( circleOverlap.overlap == 0 ){
44677 e.weight = e.length / (e.v0.radius + e.v1.radius);
44678 }
44679 else {
44680 var r1 = e.v0.radius;
44681 var r2 = e.v1.radius;
44682 var r = e.length;
44683 if( r < r1 + r2 ){
44684 if( circleOverlap.type == 'diameter' ){
44685 var ol1 = (r2-(r-r1)) / r1 / 2;
44686 var ol2 = (r1-(r-r2)) / r2 / 2;
44687 var ol = Math.max(ol1,ol2);
44688 e.weight = circleOverlap.overlap / ol;
44689 }
44690 if( circleOverlap.type == 'area' ){
44691 if( !(r+r1 < r2 || r+r2 < r1) ){
44692 var A = r2*r2*Math.acos((r*r+r2*r2-r1*r1)/(2*r*r2))+r1*r1*Math.acos((r*r+r1*r1-r2*r2)/(2*r*r1))-1/2*Math.sqrt((-r+r1+r2)*(r-r1+r2)*(r+r1-r2)*(r+r1+r2));
44693 var ol1 = A / (Math.PI*r1*r1);
44694 var ol2 = A / (Math.PI*r2*r2);
44695 var ol = Math.max(ol1,ol2);
44696 e.weight = circleOverlap.overlap / ol;
44697 }
44698 else {
44699 e.weight = 0;
44700 }
44701 }
44702 }
44703 }
44704 if (e.weight < 1) {
44705 this.deleteEdges.push(e);
44706 }
44707 }
44708 newEdges.push(e);
44709 }
44710 }
44711 this.edges = newEdges;
44712 }
44713
44714 Clustering.prototype.ValidityTest = function() {
44715 console.info("Test 1: Valid Delaunay ...");
44716 /*
44717 var leafs = [];
44718 var triangles = this.boundingTriangle.descendants;
44719 var j = 0;
44720 while( triangles.length > j ){
44721 var t = triangles[j];
44722 if( t.taken == undefined ){
44723 t.taken = true;
44724 if( this.isLeaf(t) ){
44725 leafs.push(t);
44726 }
44727 else {
44728 triangles = triangles.concat(t.descendants);
44729 }
44730 }
44731 j++;
44732 }
44733 console.info(" Number of Triangles: "+leafs.length);
44734
44735 var c = 0;
44736 for( i in this.edges ){
44737 if( this.edges[i].legal ){
44738 c++;
44739 }
44740 }
44741 console.info(" Number of Edges: "+c);*/
44742 /*
44743
44744 for( var i=0; i<leafs.length; i++ ){
44745 for( var j=0; j<vertices.length; j++ ){
44746 if( !leafs[i].contains(vertices[j]) && leafs[i].inCircumcircle(vertices[j]) ){
44747 console.info(leafs[i],vertices[j]);
44748
44749 }
44750 }
44751 }
44752 */
44753
44754 //console.info("Test 2: Edges Facets (null) ...");
44755 for (i in this.edges ) {
44756 var e = this.edges[i];
44757 if (e.leftFace == null || e.rightFace == null) {
44758 console.info(e);
44759 alert();
44760 }
44761 }
44762
44763 //console.info("Test 3: Edges Facets ...");
44764 var leftOf = function(v1, v2, v) {
44765 var x2 = v1.x - v2.x;
44766 var x3 = v1.x - v.x;
44767 var y2 = v1.y - v2.y;
44768 var y3 = v1.y - v.y;
44769 if (x2 * y3 - y2 * x3 < 0) {
44770 return true;
44771 }
44772 return false;
44773 }
44774 var c = 0;
44775 for (i in this.edges ) {
44776 var e = this.edges[i];
44777 var t1 = e.leftFace.getTriple(e);
44778 var t2 = e.rightFace.getTriple(e);
44779 if (e.v0.y == e.v1.y) {
44780 if (t1.u.y > t2.u.y) {
44781 console.info("equal y conflict ...");
44782 console.info(e);
44783 alert();
44784 c++;
44785 }
44786 } else {
44787 var v1, v2;
44788 if (e.v0.y > e.v1.y) {
44789 v1 = e.v0;
44790 v2 = e.v1;
44791 } else {
44792 v1 = e.v1;
44793 v2 = e.v0;
44794 }
44795 if (!leftOf(v1, v2, t1.u)) {
44796 console.info("left right conflict ... left is right");
44797 console.info(e);
44798 alert();
44799 c++;
44800 }
44801 if (leftOf(v1, v2, t2.u)) {
44802 console.info("left right conflict ... right is left");
44803 console.info(e);
44804 alert();
44805 c++;
44806 }
44807 }
44808 }
44809 //console.info("Number of Edges: "+this.edges.length);
44810 //console.info("Number of Conflicts: "+c);
44811
44812 for (i in this.edges ) {
44813 if (this.edges[i].legal) {
44814 var e = this.edges[i];
44815 var tr0 = e.leftFace.getTriple(e);
44816 var tr1 = e.rightFace.getTriple(e);
44817 if (!tr0.e_p.legal || !tr0.e_s.legal || !tr1.e_p.legal || !tr1.e_s.legal) {
44818 console.info(e);
44819 console.info("conflict in edge continuity");
44820 return;
44821 }
44822 }
44823 }
44824
44825 }
44826 function BinaryHeap(scoreFunction) {
44827 this.content = [];
44828 this.scoreFunction = scoreFunction;
44829 }
44830
44831 BinaryHeap.prototype = {
44832 push : function(element) {
44833 // Add the new element to the end of the array.
44834 this.content.push(element);
44835 // Allow it to bubble up.
44836 this.bubbleUp(this.content.length - 1);
44837 },
44838
44839 pop : function() {
44840 // Store the first element so we can return it later.
44841 var result = this.content[0];
44842 // Get the element at the end of the array.
44843 var end = this.content.pop();
44844 // If there are any elements left, put the end element at the
44845 // start, and let it sink down.
44846 if (this.content.length > 0) {
44847 this.content[0] = end;
44848 this.sinkDown(0);
44849 }
44850 return result;
44851 },
44852
44853 remove : function(node) {
44854 var len = this.content.length;
44855 // To remove a value, we must search through the array to find
44856 // it.
44857 for (var i = 0; i < len; i++) {
44858 if (this.content[i] == node) {
44859 // When it is found, the process seen in 'pop' is repeated
44860 // to fill up the hole.
44861 var end = this.content.pop();
44862 if (i != len - 1) {
44863 this.content[i] = end;
44864 if (this.scoreFunction(end) < this.scoreFunction(node))
44865 this.bubbleUp(i);
44866 else
44867 this.sinkDown(i);
44868 }
44869 return;
44870 }
44871 }
44872 throw new Error("Node not found.");
44873 },
44874
44875 size : function() {
44876 return this.content.length;
44877 },
44878
44879 bubbleUp : function(n) {
44880 // Fetch the element that has to be moved.
44881 var element = this.content[n];
44882 // When at 0, an element can not go up any further.
44883 while (n > 0) {
44884 // Compute the parent element's index, and fetch it.
44885 var parentN = Math.floor((n + 1) / 2) - 1, parent = this.content[parentN];
44886 // Swap the elements if the parent is greater.
44887 if (this.scoreFunction(element) < this.scoreFunction(parent)) {
44888 this.content[parentN] = element;
44889 this.content[n] = parent;
44890 // Update 'n' to continue at the new position.
44891 n = parentN;
44892
44893 }
44894 // Found a parent that is less, no need to move it further.
44895 else {
44896 break;
44897 }
44898 }
44899 },
44900
44901 sinkDown : function(n) {
44902 // Look up the target element and its score.
44903 var length = this.content.length, element = this.content[n], elemScore = this.scoreFunction(element);
44904
44905 while (true) {
44906 // Compute the indices of the child elements.
44907 var child2N = (n + 1) * 2, child1N = child2N - 1;
44908 // This is used to store the new position of the element,
44909 // if any.
44910 var swap = null;
44911 // If the first child exists (is inside the array)...
44912 if (child1N < length) {
44913 // Look it up and compute its score.
44914 var child1 = this.content[child1N], child1Score = this.scoreFunction(child1);
44915 // If the score is less than our element's, we need to swap.
44916 if (child1Score < elemScore)
44917 swap = child1N;
44918 }
44919 // Do the same checks for the other child.
44920 if (child2N < length) {
44921 var child2 = this.content[child2N], child2Score = this.scoreFunction(child2);
44922 if (child2Score < (swap == null ? elemScore : child1Score))
44923 swap = child2N;
44924 }
44925
44926 // If the element needs to be moved, swap it, and continue.
44927 if (swap != null) {
44928 this.content[n] = this.content[swap];
44929 this.content[swap] = element;
44930 n = swap;
44931 }
44932 // Otherwise, we are done.
44933 else {
44934 break;
44935 }
44936 }
44937 }
44938 };
44939 /*
44940 * Dropdown.js
44941 *
44942 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
44943 *
44944 * This library is free software; you can redistribute it and/or
44945 * modify it under the terms of the GNU Lesser General Public
44946 * License as published by the Free Software Foundation; either
44947 * version 3 of the License, or (at your option) any later version.
44948 *
44949 * This library is distributed in the hope that it will be useful,
44950 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44951 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44952 * Lesser General Public License for more details.
44953 *
44954 * You should have received a copy of the GNU Lesser General Public
44955 * License along with this library; if not, write to the Free Software
44956 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
44957 * MA 02110-1301 USA
44958 */
44959
44960 /**
44961 * @class Dropdown
44962 * Implementation for Dropdown box
44963 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
44964 * @release 1.0
44965 * @release date: 2012-07-27
44966 * @version date: 2012-07-27
44967 *
44968 * @param {HTML object} parent parent div for the dropdown box
44969 * @param {Array} elements list of dropdown entries
44970 * @param {String} title dropdown button title
44971 */
44972 function Dropdown(parent, elements, title, maxListHeight) {
44973
44974 var dropdown = this;
44975 this.visibility = false;
44976 this.div = document.createElement("div");
44977 this.div.setAttribute('class', 'dropdown');
44978
44979 this.selection = document.createElement("div");
44980 this.selection.setAttribute('class', 'dropdownSelection');
44981 parent.appendChild(this.div);
44982
44983 var leftBorder = document.createElement("div");
44984 leftBorder.setAttribute('class', 'dropdownLeft');
44985 this.div.appendChild(leftBorder);
44986
44987 this.div.appendChild(this.selection);
44988
44989 var dropdownButton = document.createElement("div");
44990 this.div.appendChild(dropdownButton);
44991 if (elements.length > 1) {
44992 dropdownButton.setAttribute('class', 'dropdownButtonEnabled');
44993 } else {
44994 dropdownButton.setAttribute('class', 'dropdownButtonDisabled');
44995 }
44996 dropdownButton.onclick = function() {
44997 if (elements.length > 1) {
44998 dropdown.changeVisibility();
44999 }
45000 }
45001 dropdownButton.title = title;
45002
45003 this.getValue = function() {
45004 return this.selectedEntry.innerHTML;
45005 };
45006
45007 var entryMenu = document.createElement("div");
45008 entryMenu.setAttribute('class', 'dropdownMenu');
45009 this.div.appendChild(entryMenu);
45010 if (typeof maxListHeight !== "undefined")
45011 $(entryMenu).height(maxListHeight);
45012
45013 var entries = document.createElement("dl");
45014 var addEntry = function(e) {
45015 var entry = document.createElement("dt");
45016 entry.setAttribute('class', 'dropdownUnselectedEntry');
45017 entry.innerHTML = e.name;
45018 entry.onclick = function() {
45019 e.onclick();
45020 dropdown.changeVisibility();
45021 dropdown.changeEntries(e);
45022 }
45023 entries.appendChild(entry);
45024 e.entry = entry;
45025 }
45026 for (var i = 0; i < elements.length; i++) {
45027 addEntry(elements[i]);
45028 }
45029 entryMenu.appendChild(entries);
45030 this.selection.style.width = entryMenu.offsetWidth + "px";
45031 entryMenu.style.width = (entryMenu.offsetWidth + leftBorder.offsetWidth + dropdownButton.offsetWidth - 2) + "px";
45032 this.div.style.maxHeight = this.div.offsetHeight + "px";
45033
45034 entryMenu.style.display = 'none';
45035
45036 this.setEntry = function(index) {
45037 if ( typeof (index) == "undefined") {
45038 if ((elements) && elements.length > 0) {
45039 this.changeEntries(elements[0]);
45040 }
45041 } else {
45042 this.changeEntries(elements[index]);
45043 }
45044 }
45045
45046 this.changeEntries = function(element) {
45047 if (this.selectedEntry) {
45048 this.selectedEntry.setAttribute('class', 'dropdownUnselectedEntry');
45049 }
45050 this.selectedEntry = element.entry;
45051 this.selectedEntry.setAttribute('class', 'dropdownSelectedEntry');
45052 this.selection.innerHTML = "<div style='display:inline-block;vertical-align:middle;'>" + element.name + "</div>";
45053 }
45054
45055 this.changeVisibility = function() {
45056 this.visibility = !this.visibility;
45057 if (this.visibility) {
45058 entryMenu.style.display = "block";
45059 } else {
45060 entryMenu.style.display = "none";
45061 }
45062 }
45063 }
45064 /*
45065 * MapZoomSlider.js
45066 *
45067 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
45068 *
45069 * This library is free software; you can redistribute it and/or
45070 * modify it under the terms of the GNU Lesser General Public
45071 * License as published by the Free Software Foundation; either
45072 * version 3 of the License, or (at your option) any later version.
45073 *
45074 * This library is distributed in the hope that it will be useful,
45075 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45076 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45077 * Lesser General Public License for more details.
45078 *
45079 * You should have received a copy of the GNU Lesser General Public
45080 * License along with this library; if not, write to the Free Software
45081 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
45082 * MA 02110-1301 USA
45083 */
45084
45085 /**
45086 * @class MapZoomSlider
45087 * GeoTemCo style for map zoom control
45088 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
45089 * @release 1.0
45090 * @release date: 2012-07-27
45091 * @version date: 2012-07-27
45092 */
45093 function MapZoomSlider(parent, orientation) {
45094
45095 this.parent = parent;
45096
45097 var zs = this;
45098 this.div = document.createElement("div");
45099 this.div.setAttribute('class', 'sliderStyle-' + orientation);
45100
45101 var sliderContainer = document.createElement("div");
45102 sliderContainer.setAttribute('class', 'zoomSliderContainer-' + orientation);
45103 var sliderDiv = document.createElement("div");
45104 sliderDiv.tabIndex = 1;
45105 var sliderInputDiv = document.createElement("div");
45106 sliderDiv.appendChild(sliderInputDiv);
45107 sliderContainer.appendChild(sliderDiv);
45108 this.slider = new Slider(sliderDiv, sliderInputDiv, orientation);
45109 this.div.appendChild(sliderContainer);
45110
45111 var zoomIn = document.createElement("img");
45112 zoomIn.src = GeoTemConfig.path + "zoom_in.png";
45113 zoomIn.setAttribute('class', 'zoomSliderIn-' + orientation);
45114 zoomIn.onclick = function() {
45115 zs.parent.zoom(1);
45116 }
45117 this.div.appendChild(zoomIn);
45118
45119 var zoomOut = document.createElement("img");
45120 zoomOut.src = GeoTemConfig.path + "zoom_out.png";
45121 zoomOut.setAttribute('class', 'zoomSliderOut-' + orientation);
45122 zoomOut.onclick = function() {
45123 zs.parent.zoom(-1);
45124 }
45125 this.div.appendChild(zoomOut);
45126
45127 this.slider.onclick = function() {
45128 console.info(zs.slider.getValue());
45129 }
45130
45131 this.slider.handle.onmousedown = function() {
45132 var oldValue = zs.slider.getValue();
45133 document.onmouseup = function() {
45134 if (!zs.parent.zoom((zs.slider.getValue() - oldValue) / zs.max * zs.levels)) {
45135 zs.setValue(oldValue);
45136 }
45137 document.onmouseup = null;
45138 }
45139 }
45140
45141 this.setValue = function(value) {
45142 this.slider.setValue(value / this.levels * this.max);
45143 }
45144
45145 this.setMaxAndLevels = function(max, levels) {
45146 this.max = max;
45147 this.levels = levels;
45148 this.slider.setMaximum(max);
45149 }
45150 // this.setMaxAndLevels(1000,parent.openlayersMap.getNumZoomLevels());
45151 // this.setValue(parent.openlayersMap.getZoom());
45152
45153 this.setLanguage = function() {
45154 zoomIn.title = GeoTemConfig.getString('zoomIn');
45155 zoomOut.title = GeoTemConfig.getString('zoomOut');
45156 this.slider.handle.title = GeoTemConfig.getString('zoomSlider');
45157 }
45158 }
45159 /*
45160 * MapPopup.js
45161 *
45162 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
45163 *
45164 * This library is free software; you can redistribute it and/or
45165 * modify it under the terms of the GNU Lesser General Public
45166 * License as published by the Free Software Foundation; either
45167 * version 3 of the License, or (at your option) any later version.
45168 *
45169 * This library is distributed in the hope that it will be useful,
45170 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45171 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45172 * Lesser General Public License for more details.
45173 *
45174 * You should have received a copy of the GNU Lesser General Public
45175 * License along with this library; if not, write to the Free Software
45176 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
45177 * MA 02110-1301 USA
45178 */
45179
45180 /**
45181 * @class MapPopup
45182 * map popup implementaion
45183 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
45184 * @release 1.0
45185 * @release date: 2012-07-27
45186 * @version date: 2012-07-27
45187 */
45188 function MapPopup(parent) {
45189
45190 this.parentDiv = parent.gui.mapWindow;
45191
45192 this.initialize = function(x, y, onclose) {
45193
45194 var popup = this;
45195 this.x = x;
45196 this.y = y;
45197
45198 this.popupDiv = document.createElement("div");
45199 this.popupDiv.setAttribute('class', 'ddbPopupDiv');
45200 this.parentDiv.appendChild(this.popupDiv);
45201
45202 this.cancel = document.createElement("div");
45203 this.cancel.setAttribute('class', 'ddbPopupCancel');
45204 this.cancel.title = GeoTemConfig.getString('close');
45205 this.cancel.onclick = function() {
45206 if ( typeof onclose != 'undefined') {
45207 onclose();
45208 }
45209 popup.reset();
45210 }
45211
45212 this.input = document.createElement("div");
45213 this.input.style.maxWidth = Math.floor(this.parentDiv.offsetWidth * 0.75) + "px";
45214 this.input.style.maxHeight = Math.floor(this.parentDiv.offsetHeight * 0.75) + "px";
45215 this.input.setAttribute('class', 'ddbPopupInput');
45216
45217 this.popupDiv.appendChild(this.input);
45218 this.popupDiv.appendChild(this.cancel);
45219
45220 var peak = document.createElement("div");
45221 peak.setAttribute('class', 'popupPeak');
45222 this.popupDiv.appendChild(peak);
45223 var topRight = document.createElement("div");
45224 topRight.setAttribute('class', 'popupTopRight');
45225 this.popupDiv.appendChild(topRight);
45226 var bottomRight = document.createElement("div");
45227 bottomRight.setAttribute('class', 'popupBottomRight');
45228 this.popupDiv.appendChild(bottomRight);
45229 this.popupRight = document.createElement("div");
45230 this.popupRight.setAttribute('class', 'popupRight');
45231 this.popupDiv.appendChild(this.popupRight);
45232 this.popupBottom = document.createElement("div");
45233 this.popupBottom.setAttribute('class', 'popupBottom');
45234 this.popupDiv.appendChild(this.popupBottom);
45235
45236 }
45237
45238 this.setContent = function(content) {
45239 $(this.input).empty();
45240 this.visible = true;
45241 $(this.input).append(content);
45242 this.decorate();
45243 }
45244
45245 this.reset = function() {
45246 $(this.popupDiv).remove();
45247 this.visible = false;
45248 }
45249
45250 this.decorate = function() {
45251 this.popupRight.style.height = (this.popupDiv.offsetHeight - 14) + "px";
45252 this.popupBottom.style.width = (this.popupDiv.offsetWidth - 22) + "px";
45253 this.left = this.x + 9;
45254 this.top = this.y - 10 - this.popupDiv.offsetHeight;
45255 this.popupDiv.style.left = this.left + "px";
45256 this.popupDiv.style.top = this.top + "px";
45257 var shiftX = 0, shiftY = 0;
45258 if (this.popupDiv.offsetTop < parent.gui.headerHeight + 10) {
45259 shiftY = -1 * (parent.gui.headerHeight + 10 - this.popupDiv.offsetTop);
45260 }
45261 if (this.popupDiv.offsetLeft + this.popupDiv.offsetWidth > parent.gui.headerWidth - 10) {
45262 shiftX = -1 * (parent.gui.headerWidth - 10 - this.popupDiv.offsetLeft - this.popupDiv.offsetWidth);
45263 }
45264 parent.shift(shiftX, shiftY);
45265 }
45266
45267 this.shift = function(x, y) {
45268 this.left = this.left - this.x + x;
45269 this.top = this.top - this.y + y;
45270 this.x = x;
45271 this.y = y;
45272 if (this.left + this.popupDiv.offsetWidth > this.parentDiv.offsetWidth) {
45273 this.popupDiv.style.left = 'auto';
45274 this.popupDiv.style.right = (this.parentDiv.offsetWidth - this.left - this.popupDiv.offsetWidth) + "px";
45275 } else {
45276 this.popupDiv.style.right = 'auto';
45277 this.popupDiv.style.left = this.left + "px";
45278 }
45279 this.popupDiv.style.top = this.top + "px";
45280 }
45281 }
45282 /*
45283 * PlacenamePopup.js
45284 *
45285 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
45286 *
45287 * This library is free software; you can redistribute it and/or
45288 * modify it under the terms of the GNU Lesser General Public
45289 * License as published by the Free Software Foundation; either
45290 * version 3 of the License, or (at your option) any later version.
45291 *
45292 * This library is distributed in the hope that it will be useful,
45293 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45294 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45295 * Lesser General Public License for more details.
45296 *
45297 * You should have received a copy of the GNU Lesser General Public
45298 * License along with this library; if not, write to the Free Software
45299 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
45300 * MA 02110-1301 USA
45301 */
45302
45303 /**
45304 * @class PlacenamePopup
45305 * specific map popup for showing and interacting on placename labels
45306 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
45307 * @release 1.0
45308 * @release date: 2012-07-27
45309 * @version date: 2012-07-27
45310 */
45311 function PlacenamePopup(parent) {
45312
45313 this.parentDiv = parent.gui.mapWindow;
45314
45315 this.createPopup = function(x, y, labels) {
45316 this.labels = labels;
45317 var pnPopup = this;
45318 var popup = new MapPopup(parent);
45319 var onClose = function() {
45320 parent.deselection();
45321 pnPopup.reset();
45322 }
45323 popup.initialize(x, y, onClose);
45324 $.extend(this, popup);
45325
45326 this.content = document.createElement("div");
45327 this.inner = document.createElement("div");
45328
45329 this.resultsLabel = document.createElement("div");
45330 this.resultsLabel.setAttribute('class', 'popupDDBResults');
45331 this.content.appendChild(this.resultsLabel);
45332 this.backward = document.createElement("div");
45333 this.backward.setAttribute('class', 'prevItem');
45334 this.content.appendChild(this.backward);
45335 this.backward.onclick = function() {
45336 pnPopup.descriptionIndex--;
45337 pnPopup.showDescription();
45338 }
45339
45340 this.number = document.createElement("div");
45341 this.content.appendChild(this.number);
45342 this.number.style.display = 'none';
45343 this.number.style.fontSize = '13px';
45344
45345 this.forward = document.createElement("div");
45346 this.forward.setAttribute('class', 'nextItem');
45347 this.content.appendChild(this.forward);
45348 this.forward.onclick = function() {
45349 pnPopup.descriptionIndex++;
45350 pnPopup.showDescription();
45351 }
45352 if (parent.options.showDescriptions) {
45353 this.descriptions = document.createElement("div");
45354 this.descriptions.setAttribute('class', 'descriptions');
45355 this.descriptions.onclick = function() {
45356 pnPopup.switchToDescriptionMode();
45357 }
45358 }
45359
45360 this.back = document.createElement("div");
45361 this.back.setAttribute('class', 'back');
45362 this.popupDiv.appendChild(this.back);
45363 this.back.onclick = function() {
45364 pnPopup.back.style.display = "none";
45365 pnPopup.backward.style.display = "none";
45366 pnPopup.forward.style.display = "none";
45367 pnPopup.number.style.display = 'none';
45368 pnPopup.showLabels();
45369 }
45370
45371 this.content.appendChild(this.inner);
45372 this.listLabels();
45373 this.showLabels();
45374
45375 };
45376
45377 this.switchToDescriptionMode = function() {
45378 this.descriptionIndex = 0;
45379 this.descriptionContents = this.activeLabel.descriptions;
45380 this.number.style.display = 'inline-block';
45381 this.inner.style.minWidth = "300px";
45382 this.showDescription();
45383 this.count = this.activeLabel.weight;
45384 this.setCount();
45385 this.back.style.display = "inline-block";
45386 }
45387
45388 this.showDescription = function() {
45389 $(this.inner).empty();
45390 this.inner.appendChild(this.descriptionContents[this.descriptionIndex]);
45391 this.setContent(this.content);
45392 if (this.descriptionContents.length == 1) {
45393 this.backward.style.display = "none";
45394 this.forward.style.display = "none";
45395 } else {
45396 if (this.descriptionIndex == 0) {
45397 this.backward.style.display = "none";
45398 } else {
45399 this.backward.style.display = "inline-block";
45400 }
45401 if (this.descriptionIndex == this.descriptionContents.length - 1) {
45402 this.forward.style.display = "none";
45403 } else {
45404 this.forward.style.display = "inline-block";
45405 }
45406 }
45407 if (this.descriptionContents.length > 1) {
45408 this.number.innerHTML = "#" + (this.descriptionIndex + 1);
45409 } else {
45410 this.number.style.display = 'none';
45411 }
45412 this.decorate();
45413 }
45414
45415 this.setCount = function() {
45416 var c = this.count;
45417 if (c > 1) {
45418 this.resultsLabel.innerHTML = c + " " + GeoTemConfig.getString('results');
45419 } else {
45420 this.resultsLabel.innerHTML = c + " " + GeoTemConfig.getString('result');
45421 }
45422 }
45423
45424 this.listLabels = function() {
45425 var pnPopup = this;
45426 this.labelDivs = [];
45427 this.labelCount = 0;
45428 this.labelsWidth = 0;
45429 for (var i = 0; i < this.labels.length; i++) {
45430 var div = document.createElement("div");
45431 var content = document.createElement("div");
45432 this.labels[i].allStyle += "position: relative; white-space: nowrap;";
45433 content.appendChild(this.labels[i].div);
45434 content.setAttribute('class', 'ddbPopupLabel');
45435 div.appendChild(content);
45436 this.labels[i].div.setAttribute('style', this.labels[i].allStyle + "" + this.labels[i].selectedStyle);
45437 this.input.appendChild(div);
45438 if (this.input.offsetWidth > this.labelsWidth) {
45439 this.labelsWidth = this.input.offsetWidth;
45440 }
45441 this.labels[i].div.setAttribute('style', this.labels[i].allStyle + "" + this.labels[i].unselectedStyle);
45442 this.labelDivs.push(div);
45443 var descriptions = [];
45444 for (var j = 0; j < this.labels[i].elements.length; j++) {
45445 var div = document.createElement("div");
45446 div.innerHTML = this.labels[i].elements[j].description;
45447 descriptions.push(div);
45448 }
45449 this.labels[i].descriptions = descriptions;
45450 if (this.labels[i].place != "all" || i == 0) {
45451 this.labelCount += this.labels[i].weight;
45452 }
45453 }
45454 if ( typeof this.descriptions != 'undefined') {
45455 this.labelsWidth += 20;
45456 }
45457 }
45458
45459 this.showLabels = function() {
45460 $(this.inner).empty();
45461 this.count = this.labelCount;
45462 this.setCount();
45463 for (var i = 0; i < this.labelDivs.length; i++) {
45464 this.inner.appendChild(this.labelDivs[i]);
45465 }
45466 this.inner.style.width = this.labelsWidth + "px";
45467 this.inner.style.minWidth = this.labelsWidth + "px";
45468 this.setContent(this.content);
45469 this.decorate();
45470 }
45471
45472 this.showLabelContent = function(label) {
45473 for (var i = 0; i < this.labels.length; i++) {
45474 if (this.labels[i] == label) {
45475 this.activeLabel = this.labels[i];
45476 if ( typeof this.descriptions != 'undefined') {
45477 this.labelDivs[i].appendChild(this.descriptions);
45478 }
45479 this.decorate();
45480 break;
45481 }
45482 }
45483 }
45484
45485 this.setLanguage = function(language) {
45486 this.language = language;
45487 if (this.visible) {
45488 this.updateTexts();
45489 }
45490 }
45491 };
45492 /*
45493 * Dropdown.js
45494 *
45495 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
45496 *
45497 * This library is free software; you can redistribute it and/or
45498 * modify it under the terms of the GNU Lesser General Public
45499 * License as published by the Free Software Foundation; either
45500 * version 3 of the License, or (at your option) any later version.
45501 *
45502 * This library is distributed in the hope that it will be useful,
45503 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45504 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45505 * Lesser General Public License for more details.
45506 *
45507 * You should have received a copy of the GNU Lesser General Public
45508 * License along with this library; if not, write to the Free Software
45509 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
45510 * MA 02110-1301 USA
45511 */
45512
45513 /**
45514 * @class Publisher
45515 * Publish/Subscribe mechanism
45516 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
45517 * @release 1.0
45518 * @release date: 2012-07-27
45519 * @version date: 2012-07-27
45520 */
45521 if ( typeof Publisher == 'undefined') {
45522
45523 Publisher = function() {
45524
45525 var topics = [];
45526
45527 this.Get = function(topic) {
45528 var value = topics[topic];
45529 if (!value || !(value instanceof Array)) {
45530 value = topics[topic] = [];
45531 }
45532 return value;
45533 };
45534
45535 this.Publish = function(topic, data, publisher) {
45536 var subscribers = this.Get(topic);
45537 for (var i = 0; i < subscribers.length; i++) {
45538 if (publisher == null || subscribers[i].client != publisher) {
45539 subscribers[i].callback(data);
45540 }
45541 }
45542 };
45543
45544 this.Subscribe = function(topic, subscriber, callback) {
45545 var subscribers = this.Get(topic);
45546 subscribers.push({
45547 client : subscriber,
45548 callback : callback
45549 });
45550 };
45551
45552 this.Unsubscribe = function(topic, unsubscriber) {
45553 var subscribers = this.Get(topic);
45554 for (var i = 0; i < subscribers.length; i++) {
45555 if (subscribers[i].client == unsubscriber) {
45556 subscribers.splice(i, 1);
45557 return;
45558 }
45559 }
45560 };
45561
45562 return this;
45563
45564 }();
45565
45566 }
45567 /*
45568 * WidgetWrapper.js
45569 *
45570 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
45571 *
45572 * This library is free software; you can redistribute it and/or
45573 * modify it under the terms of the GNU Lesser General Public
45574 * License as published by the Free Software Foundation; either
45575 * version 3 of the License, or (at your option) any later version.
45576 *
45577 * This library is distributed in the hope that it will be useful,
45578 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45579 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45580 * Lesser General Public License for more details.
45581 *
45582 * You should have received a copy of the GNU Lesser General Public
45583 * License along with this library; if not, write to the Free Software
45584 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
45585 * MA 02110-1301 USA
45586 */
45587
45588 /**
45589 * @class WidgetWrapper
45590 * Interface-like implementation for widgets interaction to each other; aimed to be modified for dynamic data sources
45591 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
45592 * @release 1.0
45593 * @release date: 2012-07-27
45594 * @version date: 2012-07-27
45595 *
45596 * @param {Object} widget either a map, time or table widget
45597 */
45598 WidgetWrapper = function() {
45599
45600 var wrapper = this;
45601
45602 this.setWidget = function(widget) {
45603 this.widget = widget;
45604 }
45605
45606 this.display = function(data) {
45607 if ( data instanceof Array) {
45608 GeoTemConfig.datasets = data;
45609 if ( typeof wrapper.widget != 'undefined') {
45610 this.widget.initWidget(data);
45611 }
45612 }
45613 };
45614
45615 Publisher.Subscribe('highlight', this, function(data) {
45616 if (data == undefined) {
45617 return;
45618 }
45619 if ( typeof wrapper.widget != 'undefined') {
45620 wrapper.widget.highlightChanged(data);
45621 }
45622 });
45623
45624 Publisher.Subscribe('selection', this, function(data) {
45625 if ( typeof wrapper.widget != 'undefined') {
45626 wrapper.widget.selectionChanged(data);
45627 }
45628 });
45629
45630 Publisher.Subscribe('filterData', this, function(data) {
45631 wrapper.display(data);
45632 });
45633
45634 Publisher.Subscribe('rise', this, function(id) {
45635 if ( typeof wrapper.widget != 'undefined' && typeof wrapper.widget.riseLayer != 'undefined') {
45636 wrapper.widget.riseLayer(id);
45637 }
45638 });
45639
45640 Publisher.Subscribe('resizeWidget', this, function() {
45641 if ( typeof wrapper.widget != 'undefined' && typeof wrapper.widget.gui != 'undefined' && typeof wrapper.widget.gui.resize != 'undefined' ) {
45642 wrapper.widget.gui.resize();
45643 }
45644 });
45645
45646 this.triggerRefining = function(datasets) {
45647 Publisher.Publish('filterData', datasets, null);
45648 };
45649
45650 this.triggerSelection = function(selectedObjects) {
45651 Publisher.Publish('selection', selectedObjects, this);
45652 };
45653
45654 this.triggerHighlight = function(highlightedObjects) {
45655 Publisher.Publish('highlight', highlightedObjects, this);
45656 };
45657
45658 this.triggerRise = function(id) {
45659 Publisher.Publish('rise', id);
45660 };
45661
45662 };
45663 /*
45664 * final.js
45665 *
45666 * Copyright (c) 2012, Stefan Jänicke. All rights reserved.
45667 *
45668 * This library is free software; you can redistribute it and/or
45669 * modify it under the terms of the GNU Lesser General Public
45670 * License as published by the Free Software Foundation; either
45671 * version 3 of the License, or (at your option) any later version.
45672 *
45673 * This library is distributed in the hope that it will be useful,
45674 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45675 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
45676 * Lesser General Public License for more details.
45677 *
45678 * You should have received a copy of the GNU Lesser General Public
45679 * License along with this library; if not, write to the Free Software
45680 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
45681 * MA 02110-1301 USA
45682 */
45683
45684 /**
45685 * code which is included after all other sources have been included for the minified version
45686 * @author Stefan Jänicke (stjaenicke@informatik.uni-leipzig.de)
45687 * @release 1.0
45688 * @release date: 2012-07-27
45689 * @version date: 2012-07-27
45690 */
45691
45692 OpenLayers.Util.getImagesLocation = function() {
45693 return GeoTemCoMinifier_urlPrefix + "lib/openlayers/img/";
45694 };
45695
45696 OpenLayers._getScriptLocation = function() {
45697 return GeoTemCoMinifier_urlPrefix + "lib/openlayers/";
45698 };
45699
45700 GeoTemConfig.configure(GeoTemCoMinifier_urlPrefix);
45701 })(jQuery);