1
|
/*
|
2
|
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
|
3
|
Dependancies: Sarissa
|
4
|
|
5
|
$Id: Util.js 3961 2008-04-01 12:45:02Z ahocevar $
|
6
|
*/
|
7
|
|
8
|
// some basic browser detection
|
9
|
var MB_IS_MOZ = (document.implementation && document.implementation.createDocument)?true:false;
|
10
|
|
11
|
/**
|
12
|
Transform an XML document using the provided XSL and use the results to build
|
13
|
a web page.
|
14
|
@constructor
|
15
|
@param xslUrl The URL of an XSL stylesheet.
|
16
|
@author Cameron Shorter - Cameron AT Shorter.net
|
17
|
*/
|
18
|
function XslProcessor(xslUrl,docNSUri) {
|
19
|
// override Sarissa configurations to prefer MSXML3, because
|
20
|
// MSXML6 does not work well with IE6SP2
|
21
|
if (!MB_IS_MOZ) {
|
22
|
_SARISSA_DOM_PROGID = Sarissa.pickRecentProgID(["Msxml2.DOMDocument.3.0", "Msxml2.DOMDocument.6.0"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);
|
23
|
_SARISSA_XMLHTTP_PROGID = Sarissa.pickRecentProgID(["Msxml2.XMLHTTP.3.0", "MSXML2.XMLHTTP.6.0"], [["XMLHTTP", 4]]);
|
24
|
_SARISSA_THREADEDDOM_PROGID = Sarissa.pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.3.0", "MSXML2.FreeThreadedDOMDocument.6.0"]);
|
25
|
_SARISSA_XSLTEMPLATE_PROGID = Sarissa.pickRecentProgID(["Msxml2.XSLTemplate.3.0", "MSXML2.XSLTemplate.6.0"], [["XSLTPROC", 2]]);
|
26
|
}
|
27
|
// get the stylesheet document
|
28
|
this.xslUrl=xslUrl;
|
29
|
this.xslDom = Sarissa.getDomDocument();
|
30
|
this.xslDom.async = false;
|
31
|
// fix some issues in IE
|
32
|
if (!MB_IS_MOZ) {
|
33
|
try {
|
34
|
// IE6 SP2 parsing bug
|
35
|
this.xslDom.validateOnParse=false;
|
36
|
// Prevent "Access denied" with external documents
|
37
|
this.xslDom.setProperty("AllowDocumentFunction", true);
|
38
|
this.xslDom.resolveExternals = true;
|
39
|
}
|
40
|
catch (e) {
|
41
|
// do nothing here, we won't get far anyway.
|
42
|
}
|
43
|
}
|
44
|
if(typeof(inlineXSL)!="undefined") {
|
45
|
xmlString = inlineXSL[_1];
|
46
|
xmlString = xmlString.replace(/DOUBLE_QUOTE/g,"\"");
|
47
|
this.xslDom = (new DOMParser()).parseFromString(xmlString, "text/xml");
|
48
|
}
|
49
|
else {
|
50
|
if(_SARISSA_IS_SAFARI){
|
51
|
var xmlhttp = new XMLHttpRequest();
|
52
|
xmlhttp.open("GET", xslUrl, false);
|
53
|
xmlhttp.send(null);
|
54
|
this.xslDom = xmlhttp.responseXML;
|
55
|
}else
|
56
|
{
|
57
|
this.xslDom.load(xslUrl);
|
58
|
}
|
59
|
}
|
60
|
if ( Sarissa.getParseErrorText(this.xslDom) != Sarissa.PARSED_OK )
|
61
|
alert(mbGetMessage("errorLoadingStylesheet", xslUrl));
|
62
|
|
63
|
this.processor = new XSLTProcessor();
|
64
|
this.processor.importStylesheet(this.xslDom);
|
65
|
|
66
|
this.docNSUri = docNSUri;
|
67
|
|
68
|
/**
|
69
|
* Transforms XML in the provided xml node according to this XSL.
|
70
|
* @param xmlNode The XML node to be transformed.
|
71
|
* @return The transformed String.
|
72
|
*/
|
73
|
this.transformNodeToString = function(xmlNode) {
|
74
|
try {
|
75
|
// transform and build a web page with result
|
76
|
//MAP-427 Quick hack to transform an XMLElement to XMLDocument in IE
|
77
|
|
78
|
if (_SARISSA_IS_IE){
|
79
|
var str = (new XMLSerializer()).serializeToString(xmlNode);
|
80
|
var xmlNode = (new DOMParser()).parseFromString(str, "text/xml");
|
81
|
}
|
82
|
var newDoc = this.transformNodeToObject(xmlNode);
|
83
|
var s = (new XMLSerializer()).serializeToString(newDoc);
|
84
|
if(_SARISSA_IS_OPERA)
|
85
|
s = s.replace(/.*\?\>/,"");//hack for opera to delete <?xml ... ?>
|
86
|
return s;
|
87
|
} catch(e){
|
88
|
alert(mbGetMessage("exceptionTransformingDoc", this.xslUrl));
|
89
|
alert("XSL="+(new XMLSerializer()).serializeToString(this.xslDom));
|
90
|
alert("XML="+(new XMLSerializer()).serializeToString(xmlNode));
|
91
|
}
|
92
|
}
|
93
|
|
94
|
/**
|
95
|
* Transforms XML in the provided xml node according to this XSL.
|
96
|
* @param xmlNode The XML node to be transformed.
|
97
|
* @return a DOM document object
|
98
|
*/
|
99
|
this.transformNodeToObject=function(xmlNode) {
|
100
|
if(_SARISSA_IS_SAFARI){
|
101
|
var oResult = new DOMParser().parseFromString("<xsltresult></xsltresult>", "text/xml");
|
102
|
var newFragment = this.processor.transformToFragment(xmlNode, oResult);
|
103
|
var str = (new XMLSerializer()).serializeToString(newFragment);
|
104
|
str.replace(/\s/g,"");
|
105
|
}else{
|
106
|
var newFragment = this.processor.transformToDocument(xmlNode);
|
107
|
}
|
108
|
return newFragment;
|
109
|
}
|
110
|
|
111
|
/**
|
112
|
* Set XSL parameter.
|
113
|
*/
|
114
|
this.setParameter=function(paramName, paramValue, nsUri) {
|
115
|
//if ( typeof paramValue == "string" || typeof paramValue == "number") paramValue="'"+paramValue+"'";
|
116
|
if (!paramValue) {
|
117
|
//alert("null value for stylesheet param:"+paramName+":"+paramValue);
|
118
|
return;
|
119
|
}
|
120
|
this.processor.setParameter( null, paramName, paramValue);
|
121
|
}
|
122
|
}
|
123
|
|
124
|
/**
|
125
|
* A more flexible interface for loading docs that allows POST and async loading
|
126
|
*/
|
127
|
function postLoad(sUri, docToSend, contentType ) {
|
128
|
var xmlHttp = new XMLHttpRequest();
|
129
|
if ( sUri.indexOf("http://")==0 || sUri.indexOf("https://")==0 ) {
|
130
|
xmlHttp.open("POST", config.proxyUrl, false);
|
131
|
xmlHttp.setRequestHeader("serverUrl",sUri);//escape(sUri).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27'));
|
132
|
} else {
|
133
|
xmlHttp.open("POST", sUri, false);
|
134
|
}
|
135
|
xmlHttp.setRequestHeader("content-type","text/xml");
|
136
|
if (contentType) xmlHttp.setRequestHeader("content-type",contentType);
|
137
|
//alert("sending:"+docToSend.xml);
|
138
|
xmlHttp.send( docToSend );
|
139
|
/*
|
140
|
if (_SARISSA_IS_IE) {
|
141
|
alert("before");
|
142
|
xmlHttp.status = xmlHttp.Status;
|
143
|
alert("after");
|
144
|
xmlHttp.statusText = xmlHttp.StatusText;
|
145
|
xmlHttp.responseText = xmlHttp.ResponseText;
|
146
|
}
|
147
|
*/
|
148
|
if (xmlHttp.status >= 400) { //http errors status start at 400
|
149
|
alert(mbGetMessage("errorLoadingDocument", sUri, xmlHttp.statusText, xmlHttp.responseText));
|
150
|
var outDoc = Sarissa.getDomDocument();
|
151
|
outDoc.parseError = -1;
|
152
|
return outDoc;
|
153
|
} else {
|
154
|
//alert(xmlHttp.getResponseHeader("Content-Type"));
|
155
|
if ( null==xmlHttp.responseXML ) alert(mbGetMessage("nullXmlResponse", xmlHttp.responseText));
|
156
|
return xmlHttp.responseXML;
|
157
|
}
|
158
|
}
|
159
|
|
160
|
|
161
|
/**
|
162
|
* A more flexible interface for loading docs that allows POST et GET param for save model
|
163
|
*/
|
164
|
|
165
|
function postGetLoad(sUri, docToSend, contentType , dir, fileName) {
|
166
|
|
167
|
var xmlHttp = new XMLHttpRequest();
|
168
|
var appendChar = sUri.indexOf("?") == -1 ? "?" : "&";
|
169
|
if(dir && fileName)
|
170
|
sUri=sUri+appendChar+"dir="+dir+"&fileName="+fileName;
|
171
|
else if(dir)
|
172
|
sUri=sUri+appendChar+"dir="+dir;
|
173
|
else if(fileName)
|
174
|
sUri=sUri+appendChar+"fileName="+fileName;
|
175
|
|
176
|
if ( sUri.indexOf("http://")==0 || sUri.indexOf("https://")==0 )
|
177
|
{
|
178
|
xmlHttp.open("POST", config.proxyUrl, false);
|
179
|
xmlHttp.setRequestHeader("serverUrl",sUri);
|
180
|
}
|
181
|
else
|
182
|
{
|
183
|
xmlHttp.open("POST", sUri, false);
|
184
|
}
|
185
|
xmlHttp.setRequestHeader("content-type","text/xml");
|
186
|
if (contentType) xmlHttp.setRequestHeader("content-type",contentType);
|
187
|
xmlHttp.send( docToSend );
|
188
|
|
189
|
if (xmlHttp.status >= 400)
|
190
|
{ //http errors status start at 400
|
191
|
alert(mbGetMessage("errorLoadingDocument", sUri, xmlHttp.statusText, xmlHttp.responseText));
|
192
|
var outDoc = Sarissa.getDomDocument();
|
193
|
outDoc.parseError = -1;
|
194
|
return outDoc;
|
195
|
}
|
196
|
else
|
197
|
{
|
198
|
if ( null==xmlHttp.responseXML ) alert(mbGetMessage("nullXmlResponse", xmlHttp.responseText));
|
199
|
return xmlHttp.responseXML;
|
200
|
}
|
201
|
}
|
202
|
|
203
|
|
204
|
|
205
|
/**
|
206
|
* If URL is local, then return URL unchanged,
|
207
|
* else return URL of http://proxy?url=URL , or null if proxy not defined.
|
208
|
* @param url Url of the file to access.
|
209
|
* @return Url of the proxy and service in the form http://host/proxy?url=service
|
210
|
*/
|
211
|
function getProxyPlusUrl(url) {
|
212
|
if ( url.indexOf("http://")==0 || url.indexOf("https://")==0 ) {
|
213
|
if ( config.proxyUrl ) {
|
214
|
url=config.proxyUrl+"?url="+escape(url).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27');
|
215
|
} else {
|
216
|
alert(mbGetMessage("unableToLoadDoc", url));
|
217
|
url=null;
|
218
|
}
|
219
|
}
|
220
|
return url;
|
221
|
}
|
222
|
|
223
|
/**
|
224
|
* Browser independant version of createElementNS()
|
225
|
* @param doc the owner document for the new element
|
226
|
* @param name for the new element
|
227
|
* @param ns the URL for the namespace (without a prefix)
|
228
|
* @return element in the document with the specified namespace
|
229
|
*/
|
230
|
function createElementWithNS(doc,name,nsUri) {
|
231
|
if (_SARISSA_IS_IE) {
|
232
|
return doc.createNode(1, name, nsUri);
|
233
|
} else {
|
234
|
return doc.createElementNS(nsUri,name);
|
235
|
}
|
236
|
}
|
237
|
|
238
|
/**
|
239
|
* Create a unique Id which can be used for classes to link themselves to HTML
|
240
|
* Ids.
|
241
|
* @constructor
|
242
|
*/
|
243
|
function UniqueId(){
|
244
|
this.lastId=0;
|
245
|
|
246
|
/** Return a numeric unique Id. */
|
247
|
this.getId=function() {
|
248
|
this.lastId++;
|
249
|
return this.lastId;
|
250
|
}
|
251
|
}
|
252
|
//use this global object to generate a unique ID via the getId function
|
253
|
var mbIds = new UniqueId();
|
254
|
|
255
|
function setISODate(isoDateStr) {
|
256
|
var parts = isoDateStr.match(/(\d{4})-?(\d{2})?-?(\d{2})?T?(\d{2})?:?(\d{2})?:?(\d{2})?\.?(\d{0,3})?(Z)?/);
|
257
|
var res = null;
|
258
|
for (var i=1;i<parts.length;++i){
|
259
|
if (!parts[i]) {
|
260
|
parts[i] = (i==3)?1:0; //months start with day number 1, not 0
|
261
|
if (!res) res = i;
|
262
|
}
|
263
|
}
|
264
|
var isoDate = new Date();
|
265
|
isoDate.setFullYear(parseInt(parts[1],10));
|
266
|
isoDate.setMonth(parseInt(parts[2],10)-1,parseInt(parts[3],10));
|
267
|
isoDate.setDate(parseInt(parts[3],10));
|
268
|
isoDate.setHours(parseInt(parts[4],10));
|
269
|
isoDate.setMinutes(parseInt(parts[5],10));
|
270
|
isoDate.setSeconds(parseFloat(parts[6],10));
|
271
|
if (!res) res = 6;
|
272
|
isoDate.res = res;
|
273
|
return isoDate;
|
274
|
}
|
275
|
|
276
|
function getISODate(isoDate) {
|
277
|
var res = isoDate.res?isoDate.res:6;
|
278
|
var dateStr = "";
|
279
|
dateStr += res>=1?isoDate.getFullYear():"";
|
280
|
dateStr += res>=2?"-"+leadingZeros(isoDate.getMonth()+1,2):"";
|
281
|
dateStr += res>=3?"-"+leadingZeros(isoDate.getDate(),2):"";
|
282
|
dateStr += res>=4?"T"+leadingZeros(isoDate.getHours(),2):"";
|
283
|
dateStr += res>=5?":"+leadingZeros(isoDate.getMinutes(),2):"";
|
284
|
dateStr += res>=6?":"+leadingZeros(isoDate.getSeconds(),2):"";
|
285
|
return dateStr;
|
286
|
}
|
287
|
|
288
|
function leadingZeros(num,digits) {
|
289
|
var intNum = parseInt(num,10);
|
290
|
var base = Math.pow(10,digits);
|
291
|
if (intNum<base) intNum += base;
|
292
|
return intNum.toString().substr(1);
|
293
|
}
|
294
|
|
295
|
|
296
|
// Correctly handle PNG transparency in Win IE 5.5 or higher.
|
297
|
// this method should be set as an IMG onload handler for PNG map layers
|
298
|
// thanks to Caroklyn Cole for this fix. For an explanation see:
|
299
|
// http://homepage.ntlworld.com/bobosola. Updated 02-March-2004
|
300
|
// modified to the images as visible after this has been called.
|
301
|
// PL-BRGM
|
302
|
// Add oldImage in parameter
|
303
|
function fixPNG(myImage,myId,oldImage) {
|
304
|
if (_SARISSA_IS_IE) {
|
305
|
// PL - BRGM
|
306
|
//opacity of the image
|
307
|
if(oldImage) {
|
308
|
var valIEOpacity= oldImage.style.filter.substring(oldImage.style.filter.indexOf('opacity=',0)+8,oldImage.style.filter.lastIndexOf(')',0));
|
309
|
if(oldImage.style.filter.indexOf('opacity=',0) ==-1){
|
310
|
valIEOpacity = null;
|
311
|
}
|
312
|
var _opacity= (valIEOpacity)?valIEOpacity/100:-1;
|
313
|
}
|
314
|
// END
|
315
|
var imgID = "id='" + myId + "' ";
|
316
|
var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : ""
|
317
|
var imgTitle = (myImage.title) ? "title='" + myImage.title + "' " : "title='" + myImage.alt + "' "
|
318
|
var imgStyle = "display:inline-block;" + myImage.style.cssText
|
319
|
var strNewHTML = "<span " + imgID + imgClass + imgTitle
|
320
|
|
321
|
strNewHTML += " style=\"" + "width:" + myImage.width + "px; height:" + myImage.height + "px;" + imgStyle + ";"
|
322
|
// store the opacity in the style even not used by IE
|
323
|
if (_opacity!=-1) strNewHTML += "opacity=" + _opacity + ";" ;
|
324
|
// Escape some chars (don't use encode() that would escape %xx previously used in XSL)
|
325
|
var src = myImage.src;
|
326
|
src = src.replace(/\(/g,'%28');
|
327
|
src = src.replace(/\)/g,'%29');
|
328
|
src = src.replace(/'/g,'%27');
|
329
|
// AlphaImageLoader converts '%23' in src to '#' and cuts URL on '#'
|
330
|
src = src.replace(/%23/g,'%2523');
|
331
|
strNewHTML += "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader";
|
332
|
strNewHTML += "(src=\'" + src + "\', sizingMethod='scale')";
|
333
|
|
334
|
// PL - BRGM
|
335
|
// add the opacity
|
336
|
if (oldImage && _opacity!=-1) strNewHTML += " alpha(opacity=" + (_opacity * 100) + ")";
|
337
|
strNewHTML +="; \"></span>" ;
|
338
|
// END PL - BRGM
|
339
|
//myImage.outerHTML = strNewHTML;
|
340
|
//alert(strNewHTML);
|
341
|
return strNewHTML;
|
342
|
}
|
343
|
}
|
344
|
|
345
|
|
346
|
|
347
|
/**
|
348
|
* get the absolute position of HTML element NS4, IE4/5 & NS6, even if it's in a table.
|
349
|
* @param element The HTML element.
|
350
|
* @return Top left X position.
|
351
|
*/
|
352
|
function getAbsX(elt) {
|
353
|
return (elt.x) ? elt.x : getAbsPos(elt,"Left") + 2;
|
354
|
}
|
355
|
|
356
|
/**
|
357
|
* get the absolute position of HTML element NS4, IE4/5 & NS6, even if it's in a table.
|
358
|
* @param element The HTML element.
|
359
|
* @return Top left Y position.
|
360
|
*/
|
361
|
function getAbsY(elt) {
|
362
|
return (elt.y) ? elt.y : getAbsPos(elt,"Top") + 2;
|
363
|
}
|
364
|
|
365
|
/**
|
366
|
* TBD: Comment me.
|
367
|
* @param elt TBD
|
368
|
* @param which TBD
|
369
|
*/
|
370
|
function getAbsPos(elt,which) {
|
371
|
iPos = 0;
|
372
|
while (elt != null) {
|
373
|
iPos += elt["offset" + which];
|
374
|
elt = elt.offsetParent;
|
375
|
}
|
376
|
return iPos;
|
377
|
}
|
378
|
|
379
|
/**
|
380
|
* get the absolute position of a user event (e.g., a mousedown).
|
381
|
* @param e The user event.
|
382
|
* @return Left or top position.
|
383
|
*/
|
384
|
function getPageX(e){
|
385
|
var posx = 0;
|
386
|
if (!e) var e = window.event;
|
387
|
if (e.pageX) {
|
388
|
posx = e.pageX;
|
389
|
}
|
390
|
else if (e.clientX) {
|
391
|
posx = e.clientX;
|
392
|
}
|
393
|
if (document.body && document.body.scrollLeft){
|
394
|
posx += document.body.scrollLeft;
|
395
|
}
|
396
|
else if (document.documentElement && document.documentElement.scrollLeft){
|
397
|
posx += document.documentElement.scrollLeft;
|
398
|
}
|
399
|
return posx;
|
400
|
}
|
401
|
|
402
|
/**
|
403
|
* get the absolute position of a user event (e.g., a mousedown).
|
404
|
* @param e The user event.
|
405
|
* @return Left or top position.
|
406
|
*/
|
407
|
function getPageY(e){
|
408
|
var posy = 0;
|
409
|
if (!e) var e = window.event;
|
410
|
if (e.pageY) {
|
411
|
posy = e.pageY;
|
412
|
}
|
413
|
else if (e.clientY) {
|
414
|
posy = e.clientY;
|
415
|
}
|
416
|
if (document.body && document.body.scrollTop){
|
417
|
posy += document.body.scrollTop;
|
418
|
}
|
419
|
else if (document.documentElement && document.documentElement.scrollTop){
|
420
|
posy += document.documentElement.scrollTop;
|
421
|
}
|
422
|
return posy;
|
423
|
}
|
424
|
|
425
|
/**
|
426
|
* parse comma-separated name=value argument pairs from the query string of the URL; the function stores name=value pairs in properties of an object and returns that object.
|
427
|
* @return args Array of arguments passed to page, in form args[argname] = value.
|
428
|
*/
|
429
|
function getArgs(){
|
430
|
var args = new Object();
|
431
|
var query = location.search.substring(1);
|
432
|
var pairs = query.split("&");
|
433
|
for(var i = 0; i < pairs.length; i++) {
|
434
|
var pos = pairs[i].indexOf('=');
|
435
|
if (pos == -1) continue;
|
436
|
var argname = pairs[i].substring(0,pos);
|
437
|
var value = pairs[i].substring(pos+1);
|
438
|
args[argname] = unescape(value.replace(/\+/g, " "));
|
439
|
}
|
440
|
return args;
|
441
|
}
|
442
|
//initialize the array once
|
443
|
window.cgiArgs = getArgs();
|
444
|
|
445
|
/**
|
446
|
* convert geographic x coordinate to screen coordinate.
|
447
|
* @param context The context object.
|
448
|
* @param xCoord The geographic x coordinate to be converted.
|
449
|
* @return x the converted x coordinate.
|
450
|
*/
|
451
|
function getScreenX(context, xCoord){
|
452
|
bbox=context.getBoundingBox();
|
453
|
width=context.getWindowWidth();
|
454
|
bbox[0]=parseFloat(bbox[0]);
|
455
|
bbox[2]=parseFloat(bbox[2]);
|
456
|
var xfac = (width/(bbox[2]-bbox[0]));
|
457
|
x=xfac*(xCoord-bbox[0]);
|
458
|
return x;
|
459
|
}
|
460
|
|
461
|
/**
|
462
|
* convert geographic y coordinate to screen coordinate.
|
463
|
* @param context The context object.
|
464
|
* @param yCoord The geographic x coordinate to be converted.
|
465
|
* @return y the converted x coordinate.
|
466
|
*/
|
467
|
function getScreenY(context, yCoord){
|
468
|
var bbox=context.getBoundingBox();
|
469
|
var height=context.getWindowHeight();
|
470
|
bbox[1]=parseFloat(bbox[1]);
|
471
|
bbox[3]=parseFloat(bbox[3]);
|
472
|
var yfac = (heighteight/(bbox[3]-bbox[1]));
|
473
|
var y=height-(yfac*(pt.y-bbox[1]));
|
474
|
return y;
|
475
|
}
|
476
|
|
477
|
/**
|
478
|
* convert screen x coordinate to geographic coordinate.
|
479
|
* @param context The context object.
|
480
|
* @param xCoord The screen x coordinate to be converted.
|
481
|
* @return x the converted x coordinate.
|
482
|
*/
|
483
|
function getGeoCoordX(context, xCooord) {
|
484
|
var bbox=context.getBoundingBox();
|
485
|
var width=context.getWindowWidth();
|
486
|
bbox[0]=parseFloat(bbox[0]);
|
487
|
bbox[2]=parseFloat(bbox[2]);
|
488
|
var xfac = ((bbox[2]-bbox[0]) / width);
|
489
|
var x=bbox[0] + xfac*(xCoord);
|
490
|
return x;
|
491
|
}
|
492
|
|
493
|
/**
|
494
|
* convert screen coordinate to screen coordinate.
|
495
|
* @param context The context object.
|
496
|
* @param yCoord The geographic y coordinate to be converted.
|
497
|
* @return y the converted y coordinate.
|
498
|
*/
|
499
|
function getGeoCoordY(yCoord){
|
500
|
var bbox=context.getBoundingBox();
|
501
|
var height=context.getWindowHeight();
|
502
|
bbox[1]=parseFloat(bbox[1]);
|
503
|
bbox[3]=parseFloat(bbox[3]);
|
504
|
var yfac = ((bbox[3]-bbox[1]) / height);
|
505
|
var y=bbox[1] + yfac*(height-yCoord);
|
506
|
return y;
|
507
|
}
|
508
|
|
509
|
/**
|
510
|
* create an element and append it to the document body element.
|
511
|
* @param type The type of element to be created.
|
512
|
* @return node The node created and appended.
|
513
|
*/
|
514
|
function makeElt(type) {
|
515
|
var node=document.createElement(type);
|
516
|
document.getElementsByTagName("body").item(0).appendChild(node);
|
517
|
return node;
|
518
|
}
|
519
|
|
520
|
// variable needed to determine if a popup window is currently open
|
521
|
var newWindow = '';
|
522
|
/**
|
523
|
* open a popup window, adapted from http://www.quirksmode.org/js/croswin.html
|
524
|
* @param url The url of the page to be opened.
|
525
|
* @param width Width of the popup window, in pixels.
|
526
|
* @param height Height of the popup window, in pixels.
|
527
|
*/
|
528
|
function openPopup(url, width, height) {
|
529
|
if(width == null) {
|
530
|
width = 300;
|
531
|
}
|
532
|
if(height == null) {
|
533
|
height = 200;
|
534
|
}
|
535
|
if (!newWindow.closed && newWindow.location) {
|
536
|
newWindow.location.href = url;
|
537
|
}
|
538
|
else {
|
539
|
newWindow=window.open(url,'name','height=' + height + ',width=' + width);
|
540
|
if (!newWindow.opener) newwindow.opener = self;
|
541
|
}
|
542
|
if (window.focus) {newWindow.focus()}
|
543
|
return false;
|
544
|
}
|
545
|
|
546
|
/**
|
547
|
* write debugging info to a textbox onscreen.
|
548
|
* @param output String to be output.
|
549
|
*/
|
550
|
function debug(output){
|
551
|
tarea=makeElt("textarea");
|
552
|
tarea.setAttribute("rows","3");
|
553
|
tarea.setAttribute("cols","40");
|
554
|
tnode=document.createTextNode(output);
|
555
|
tarea.appendChild(tnode);
|
556
|
}
|
557
|
|
558
|
/**
|
559
|
* determine and return the target element of an event.
|
560
|
* @param evt The event.
|
561
|
* @return elt The element.
|
562
|
*/
|
563
|
function returnTarget(evt){
|
564
|
evt = (evt) ? evt : ((window.event) ? window.event : "");
|
565
|
var elt=null;
|
566
|
if(evt.target){
|
567
|
elt=evt.target;
|
568
|
}
|
569
|
else if(evt.srcElement){
|
570
|
elt=evt.srcElement;
|
571
|
}
|
572
|
return elt;
|
573
|
}
|
574
|
|
575
|
/**
|
576
|
* attach an event to an element.
|
577
|
* @param elementObject The object.
|
578
|
* @param eventName The name of the event.
|
579
|
* @param functionObject The function to be called.
|
580
|
*/
|
581
|
function addEvent(elementObject, eventName, functionObject) {
|
582
|
if(document.addEventListener) {
|
583
|
elementObject.addEventListener(eventName, functionObject, false);
|
584
|
}
|
585
|
else if(document.attachEvent) {
|
586
|
elementObject.attachEvent("on" + eventName, functionObject);
|
587
|
}
|
588
|
}
|
589
|
|
590
|
/**
|
591
|
* handle event attached to an object.
|
592
|
* @param evt The event.
|
593
|
*/
|
594
|
function handleEventWithObject(evt){
|
595
|
var elt = returnTarget(evt);
|
596
|
var obj = elt.ownerObj;
|
597
|
if (obj!=null) obj.handleEvent(evt);
|
598
|
}
|
599
|
|
600
|
/**
|
601
|
* Show a message if the debug property of the object has been set.
|
602
|
* @param object the object that possibly has the debug property set
|
603
|
* @param message the message to show
|
604
|
*/
|
605
|
function mbDebugMessage(object, message)
|
606
|
{
|
607
|
if (object && object.debug) {
|
608
|
alert(message);
|
609
|
}
|
610
|
}
|
611
|
|
612
|
/**
|
613
|
* Get a message from the <code>widgetText</code> file and format it if extra
|
614
|
* arguments are passed.
|
615
|
* @param messageKey the message key within the message node
|
616
|
* @param varArgs optional extra parameters for formatting the message
|
617
|
* @return <code>"NoMsgsFound"</code> if the <code>widgetText</code> file is not found,<br/>
|
618
|
* the <code>messageKey</code> if the message key was not found within the message node,<br/>
|
619
|
* the (formatted) message if it was found
|
620
|
*/
|
621
|
function mbGetMessage(messageKey)
|
622
|
{
|
623
|
var message = "NoMsgsFound";
|
624
|
if (config.widgetText) {
|
625
|
var msgKeyXpath = "/mb:WidgetText/mb:messages/mb:" + messageKey;
|
626
|
var msgKeyNodes = config.widgetText.selectNodes(msgKeyXpath);
|
627
|
if (!msgKeyNodes || msgKeyNodes.length == 0) {
|
628
|
// Message not found, fall back to message key
|
629
|
message = messageKey;
|
630
|
}
|
631
|
else {
|
632
|
// Message found; pick last one so user can override messages
|
633
|
message = getNodeValue(msgKeyNodes.item(msgKeyNodes.length-1));
|
634
|
if (arguments[mbGetMessage.length]) {
|
635
|
// Extra arguments, format message
|
636
|
var varArgs = [].slice.call(arguments, mbGetMessage.length);
|
637
|
varArgs.unshift(message);
|
638
|
message = mbFormatMessage.apply(this, varArgs);
|
639
|
}
|
640
|
}
|
641
|
}
|
642
|
return message;
|
643
|
}
|
644
|
|
645
|
/**
|
646
|
* Format a message with the extra arguments. <br/>
|
647
|
* E.g. if called as: <code>mbFormatMessage("{1} is {0} {2}, {1}", "a good", "this", "test")</code><br/>
|
648
|
* the formatted message returned is: <code>"this is a good test, this"</code>
|
649
|
* @param messageFormat the message format string
|
650
|
* @param varArgs optional extra parameters for formatting the message
|
651
|
* @return the formatted message
|
652
|
*/
|
653
|
function mbFormatMessage(messageFormat)
|
654
|
{
|
655
|
var message = messageFormat;
|
656
|
var varArgs = [].slice.call(arguments, mbFormatMessage.length);
|
657
|
for (var i=0; i<varArgs.length; i++) {
|
658
|
var parm = new RegExp("\\{" + i + "\\}", "g");
|
659
|
message = message.replace(parm, varArgs[i]);
|
660
|
}
|
661
|
return message;
|
662
|
}
|
663
|
|
664
|
/**
|
665
|
* extract a style from a SLD node of an XML doc and return
|
666
|
* it as url parameter for a WMS request
|
667
|
* @param node XML node containing the styled layer descriptor
|
668
|
* @return WMS-compliant SLD URL parameters as array
|
669
|
*/
|
670
|
function sld2UrlParam(node) {
|
671
|
var params=new Array();
|
672
|
if (node) {
|
673
|
var sld = node.selectSingleNode("wmc:SLD");
|
674
|
var name = node.selectSingleNode("wmc:Name");
|
675
|
if(sld) {
|
676
|
if(sld.selectSingleNode("wmc:OnlineResource")) {
|
677
|
params.sld=sld.selectSingleNode("wmc:OnlineResource").getAttribute("xlink:href");
|
678
|
} else if(sld.selectSingleNode("wmc:FeatureTypeStyle")) {
|
679
|
params.sld=(new XMLSerializer()).serializeToString(sld.selectSingleNode("wmc:FeatureTypeStyle"));
|
680
|
} else if(sld.selectSingleNode("wmc:StyledLayerDescriptor")) {
|
681
|
params.sld_body=(new XMLSerializer()).serializeToString(sld.selectSingleNode("wmc:StyledLayerDescriptor"));
|
682
|
}
|
683
|
} else if(name) {
|
684
|
params.styles = getNodeValue(name) || "";
|
685
|
}
|
686
|
}
|
687
|
return params;
|
688
|
}
|
689
|
|
690
|
/**
|
691
|
* extract a style from a SLD node of an XML doc and return
|
692
|
* it as OpenLayers style
|
693
|
* @param objRef reference to the map widget that will use the style
|
694
|
* @param node XML node containing the styled layer descriptor
|
695
|
* @return OpenLayers style object
|
696
|
*/
|
697
|
function sld2OlStyle(node) {
|
698
|
// OpenLayers SLD parsing
|
699
|
if (node) {
|
700
|
var ruleNode = node.selectSingleNode("wmc:SLD/sld:FeatureTypeStyle");
|
701
|
if (ruleNode) {
|
702
|
var sld = new XMLSerializer().serializeToString(ruleNode);
|
703
|
var search = /<([^:]*:?)StyledLayerDescriptor/;
|
704
|
if (!search.test(sld)) {
|
705
|
sld = sld.replace(/<([^:]*:?)FeatureTypeStyle([^>]*)>(.*)$/,
|
706
|
"<$1StyledLayerDescriptor$2><$1NamedLayer><$1Name>sld</$1Name><$1UserStyle><$1FeatureTypeStyle>$3</$1UserStyle></$1NamedLayer></$1StyledLayerDescriptor>");
|
707
|
}
|
708
|
}
|
709
|
var styles = new OpenLayers.Format.SLD().read(sld);
|
710
|
if (styles) {
|
711
|
return styles.namedLayers["sld"].userStyles[0];
|
712
|
}
|
713
|
}
|
714
|
|
715
|
// fallback to native SLD parsing for older OwsContext docs
|
716
|
|
717
|
// sld-conform default style
|
718
|
var defaultStyle = {
|
719
|
fillColor: "#808080",
|
720
|
fillOpacity: 1,
|
721
|
strokeColor: "#000000",
|
722
|
strokeOpacity: 1,
|
723
|
strokeWidth: 1,
|
724
|
pointRadius: 6};
|
725
|
|
726
|
var style1=OpenLayers.Util.extend(defaultStyle,OpenLayers.Feature.Vector.style["default"]);
|
727
|
var value;
|
728
|
var styleSet=false;
|
729
|
|
730
|
if (node) {
|
731
|
value=node.selectSingleNode(".//sld:ExternalGraphic/sld:OnlineResource/@xlink:href");
|
732
|
if(value){
|
733
|
style1.externalGraphic=getNodeValue(value);
|
734
|
styleSet=true;
|
735
|
}
|
736
|
value=node.selectSingleNode(".//sld:Fill/sld:CssParameter[@name='fill']");
|
737
|
if(value){
|
738
|
style1.fillColor=getNodeValue(value);
|
739
|
styleSet=true;
|
740
|
}
|
741
|
value=node.selectSingleNode(".//sld:Fill/sld:CssParameter[@name='fill-opacity']");
|
742
|
if(value){
|
743
|
style1.fillOpacity=getNodeValue(value);
|
744
|
styleSet=true;
|
745
|
} else {
|
746
|
// opacity eg. for externalGraphic
|
747
|
value=node.selectSingleNode(".//sld:Opacity/sld:Literal");
|
748
|
if (value){
|
749
|
style1.fillOpacity=getNodeValue(value);
|
750
|
styleSet=true;
|
751
|
}
|
752
|
}
|
753
|
|
754
|
value=node.selectSingleNode(".//sld:Stroke/sld:CssParameter[@name='stroke']");
|
755
|
if(value){
|
756
|
style1.strokeColor=getNodeValue(value);
|
757
|
styleSet=true;
|
758
|
}
|
759
|
|
760
|
value=node.selectSingleNode(".//sld:Stroke/sld:CssParameter[@name='stroke-opacity']");
|
761
|
if(value){
|
762
|
style1.strokeOpacity=getNodeValue(value);
|
763
|
styleSet=true;
|
764
|
}
|
765
|
|
766
|
value=node.selectSingleNode(".//sld:Stroke/sld:CssParameter[@name='stroke-width']");
|
767
|
if(value){
|
768
|
style1.strokeWidth=getNodeValue(value);
|
769
|
styleSet=true;
|
770
|
}
|
771
|
|
772
|
value=node.selectSingleNode(".//sld:Size");
|
773
|
if(value){
|
774
|
style1.pointRadius=getNodeValue(value);
|
775
|
styleSet=true;
|
776
|
}
|
777
|
}
|
778
|
|
779
|
if(!styleSet)style1=null;
|
780
|
return style1;
|
781
|
}
|
782
|
|
783
|
/**
|
784
|
* Dynamically loads a stylesheet into the html page.
|
785
|
* @param cssFileName name of the file to load, relative to config.skinDir
|
786
|
*/
|
787
|
function loadCss(cssFileName) {
|
788
|
// queue the request if we do not know the skinDir yet
|
789
|
if (typeof config == "undefined" || typeof config.skinDir != "string") {
|
790
|
if (!mapbuilder.cssToLoad) {
|
791
|
mapbuilder.cssToLoad = [];
|
792
|
}
|
793
|
mapbuilder.cssToLoad.push(cssFileName);
|
794
|
return;
|
795
|
}
|
796
|
|
797
|
var id = cssFileName.match(/[^\/]*$/).toString().replace(/./, '_');
|
798
|
if (!document.getElementById(id)) {
|
799
|
var cssNode = document.createElement('link');
|
800
|
cssNode.setAttribute('id', id);
|
801
|
cssNode.setAttribute('rel', 'stylesheet');
|
802
|
cssNode.setAttribute('type', 'text/css');
|
803
|
cssNode.setAttribute('href', config.skinDir+'/'+cssFileName);
|
804
|
document.getElementsByTagName('head')[0].appendChild(cssNode);
|
805
|
}
|
806
|
}
|
807
|
|
808
|
/**
|
809
|
* getNodevalue return value of node
|
810
|
* it as OpenLayers style
|
811
|
* @param node
|
812
|
* @return return node's value
|
813
|
*/
|
814
|
function getNodeValue(sResult){
|
815
|
if(sResult.nodeType == 1) return sResult.firstChild ? sResult.firstChild.nodeValue : "";
|
816
|
if(sResult.nodeType < 5) return sResult.nodeValue;
|
817
|
return sResult;
|
818
|
}
|
819
|
|
820
|
/**
|
821
|
* Convenience method that is used to parse dom nodes.
|
822
|
* @param domNode node to find the property in
|
823
|
* @param propertyName string of the property name (including namespace prefix)
|
824
|
* @param defaultValue value to return if property is not found (null by default)
|
825
|
* @return the property value
|
826
|
*/
|
827
|
Mapbuilder.getProperty = function(domNode, propertyName, defaultValue) {
|
828
|
if (typeof defaultValue == "undefined") {
|
829
|
defaultValue = null;
|
830
|
}
|
831
|
var property = domNode.selectSingleNode(propertyName);
|
832
|
return property ? getNodeValue(property) : defaultValue;
|
833
|
}
|
834
|
|
835
|
/**
|
836
|
* Convenience method to parse a string or number as a boolean value
|
837
|
* @param value string (true/false) or number (1/0)
|
838
|
* @return boolean value, default false
|
839
|
*/
|
840
|
Mapbuilder.parseBoolean = function(value) {
|
841
|
var result = false;
|
842
|
if (!value) {
|
843
|
result = false;
|
844
|
} else if (value == 0) {
|
845
|
result = false;
|
846
|
} else if (value == 1) {
|
847
|
result = true;
|
848
|
} else if (value.match(/true/i)) {
|
849
|
result = true;
|
850
|
} else if (value.match(/false/i)){
|
851
|
return false;
|
852
|
}
|
853
|
return result;
|
854
|
}
|