Project

General

Profile

1
/*
2
License:      LGPL as per: http://www.gnu.org/copyleft/lesser.html
3
Dependancies: Sarissa
4

    
5
$Id$
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
  // get the stylesheet document
20
  this.xslUrl=xslUrl;
21
  this.xslDom = Sarissa.getDomDocument();
22
  this.xslDom.async = false;
23
  this.xslDom.validateOnParse=false;  //IE6 SP2 parsing bug
24
  this.xslDom.load(xslUrl);
25
  if ( this.xslDom.parseError < 0 )
26
    alert("error loading XSL stylesheet: " + xslUrl);
27

    
28
  this.processor = new XSLTProcessor();
29
  this.processor.importStylesheet(this.xslDom);
30

    
31
  this.docNSUri = docNSUri;
32

    
33
  /**
34
   * Transforms XML in the provided xml node according to this XSL.
35
   * @param xmlNode The XML node to be transformed.
36
   * @return The transformed String.
37
   */
38
  this.transformNodeToString = function(xmlNode) {
39
    try {
40
      // transform and build a web page with result
41
      var newDoc = this.transformNodeToObject(xmlNode);
42
      var s = Sarissa.serialize(newDoc);
43
      return Sarissa.unescape(s);
44
    } catch(e){
45
      alert("Exception transforming doc with XSL: " + this.xslUrl);
46
      alert("XSL="+Sarissa.serialize(this.xslDom));
47
      alert("XML="+Sarissa.serialize(xmlNode));
48
    }
49
  }
50

    
51
  /**
52
   * Transforms XML in the provided xml node according to this XSL.
53
   * @param xmlNode The XML node to be transformed.
54
   * @return a DOM document object
55
   */
56
  this.transformNodeToObject=function(xmlNode) {
57
    var newFragment = this.processor.transformToDocument(xmlNode);
58
    return newFragment;
59
  }
60

    
61
  /**
62
   * Set XSL parameter.
63
   */
64
  this.setParameter=function(paramName, paramValue, nsUri) {
65
    //if ( typeof paramValue == "string" || typeof paramValue == "number") paramValue="'"+paramValue+"'";
66
    if (!paramValue) {
67
      //alert("null value for stylesheet param:"+paramName+":"+paramValue);
68
      return;
69
    }
70
    this.processor.setParameter( null, paramName, paramValue);
71
  }
72
}
73

    
74
/**
75
 * A more flexible interface for loading docs that allows POST and async loading
76
 */
77
function postLoad(sUri, docToSend, contentType ) {
78
   var xmlHttp = new XMLHttpRequest();
79
   if ( sUri.indexOf("http://")==0 ) {
80
     xmlHttp.open("POST", config.proxyUrl, false);
81
     xmlHttp.setRequestHeader("serverUrl",sUri);//escape(sUri).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27'));
82
   } else {
83
     xmlHttp.open("POST", sUri, false);
84
   }
85
   xmlHttp.setRequestHeader("content-type","text/xml");
86
   if (contentType) xmlHttp.setRequestHeader("content-type",contentType);
87
   //alert("sending:"+docToSend.xml);
88
   xmlHttp.send( docToSend );
89
/*
90
   if (_SARISSA_IS_IE) {
91
alert("before");
92
    xmlHttp.status = xmlHttp.Status;
93
alert("after");
94
    xmlHttp.statusText = xmlHttp.StatusText;
95
    xmlHttp.responseText = xmlHttp.ResponseText;
96
   }
97
*/
98
   if (xmlHttp.status >= 400) {   //http errors status start at 400
99
      alert("error loading document: " + sUri + " - " + xmlHttp.statusText + "-" + xmlHttp.responseText );
100
      var outDoc = Sarissa.getDomDocument();
101
      outDoc.parseError = -1;
102
      return outDoc;
103
   } else {
104
     //alert(xmlHttp.getResponseHeader("Content-Type"));
105
     if ( null==xmlHttp.responseXML ) alert( "null XML response:" + xmlHttp.responseText );
106
     return xmlHttp.responseXML;
107
   }
108
}
109

    
110
  /**
111
   * If URL is local, then return URL unchanged,
112
   * else return URL of http://proxy?url=URL , or null if proxy not defined.
113
   * @param url Url of the file to access.
114
   * @return Url of the proxy and service in the form http://host/proxy?url=service
115
   */
116
function getProxyPlusUrl(url) {
117
  if ( url.indexOf("http://")==0 ) {
118
    if ( config.proxyUrl ) {
119
      url=config.proxyUrl+"?url="+escape(url).replace(/\+/g, '%2C').replace(/\"/g,'%22').replace(/\'/g, '%27');
120
    } else {
121
      alert("unable to load external document:"+url+"  Set the proxyUrl property in config.");
122
      url=null;
123
    }
124
  }
125
  return url;
126
}
127

    
128
  /**
129
   * Browser independant version of createElementNS() because creating elements
130
   * with namespaces other than the defalut namespace isn't dupported in IE,
131
   * or at least I can't figure out how to do it.  
132
   * Caution: In IE the new element doesn't appear to a namespace!!
133
   * @param doc the owner document for the new element
134
   * @param name the name for the new element
135
   * @param ns the URL for the namespace (without a prefix)
136
   * @return element in the document with the specified namespace
137
   */
138
function createElementWithNS(doc,name,nsUri) {
139
  if (_SARISSA_IS_IE) {
140
    var newElement = doc.createElement(name);
141
    //newElement.namespaceURI = nsUri;  //can't do this for some reason?
142
    return newElement;
143
  } else {
144
    return doc.createElementNS(nsUri,name);
145
  }
146
}
147

    
148
/**
149
 * Create a unique Id which can be used for classes to link themselves to HTML
150
 * Ids.
151
 * @constructor
152
 */
153
function UniqueId(){
154
  this.lastId=0;
155

    
156
  /** Return a numeric unique Id. */
157
  this.getId=function() {
158
    this.lastId++;
159
    return this.lastId;
160
  }
161
}
162
//use this global object to generate a unique ID via the getId function
163
var mbIds = new UniqueId();
164

    
165
function setISODate(isoDateStr) {
166
  var parts = isoDateStr.match(/(\d{4})-?(\d{2})?-?(\d{2})?T?(\d{2})?:?(\d{2})?:?(\d{2})?\.?(\d{0,3})?(Z)?/);
167
  var res = null;
168
  for (var i=1;i<parts.length;++i){
169
    if (!parts[i]) {
170
      parts[i] = (i==3)?1:0; //months start with day number 1, not 0
171
      if (!res) res = i;
172
    }
173
  }
174
  var isoDate = new Date();
175
  isoDate.setFullYear(parseInt(parts[1],10));
176
  isoDate.setMonth(parseInt(parts[2]-1,10));
177
  isoDate.setDate(parseInt(parts[3],10));
178
  isoDate.setHours(parseInt(parts[4],10));
179
  isoDate.setMinutes(parseInt(parts[5],10));
180
  isoDate.setSeconds(parseFloat(parts[6],10));
181
  if (!res) res = 6;
182
  isoDate.res = res;
183
  return isoDate;
184
}
185

    
186
function getISODate(isoDate) {
187
  var res = isoDate.res?isoDate.res:6;
188
  var dateStr = "";
189
  dateStr += res>1?isoDate.getFullYear():"";
190
  dateStr += res>2?"-"+leadingZeros(isoDate.getMonth()+1,2):"";
191
  dateStr += res>3?"-"+leadingZeros(isoDate.getDate(),2):"";
192
  dateStr += res>4?"T"+leadingZeros(isoDate.getHours(),2):"";
193
  dateStr += res>5?":"+leadingZeros(isoDate.getMinutes(),2):"";
194
  dateStr += res>6?":"+leadingZeros(isoDate.getSeconds(),2):"";
195
  return dateStr;
196
}
197

    
198
function leadingZeros(num,digits) {
199
  var intNum = parseInt(num,10);
200
  var base = Math.pow(10,digits);
201
  if (intNum<base) intNum += base;
202
  return intNum.toString().substr(1);
203
}
204

    
205

    
206
// Correctly handle PNG transparency in Win IE 5.5 or higher.
207
// this method should be set as an IMG onload handler for PNG map layers
208
// thanks to Caroklyn Cole for this fix.  For an explanation see:
209
// http://homepage.ntlworld.com/bobosola. Updated 02-March-2004
210
// modified to the images as visible after this has been called.
211
function fixPNG(myImage,myId) {
212
  if (_SARISSA_IS_IE) {
213
    var imgID = "id='" + myId + "' ";
214
    var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : ""
215
    var imgTitle = (myImage.title) ? "title='" + myImage.title + "' " : "title='" + myImage.alt + "' "
216
    var imgStyle = "display:inline-block;" + myImage.style.cssText 
217
    var strNewHTML = "<span " + imgID + imgClass + imgTitle
218
    strNewHTML += " style=\"" + "width:" + myImage.width + "px; height:" + myImage.height + "px;" + imgStyle + ";"
219
    // Escape some chars (don't use encode() that would escape %xx previously used in XSL)
220
    var src = myImage.src;
221
    src = src.replace(/\(/g,'%28');
222
    src = src.replace(/\)/g,'%29');
223
    src = src.replace(/'/g,'%27');
224
    // AlphaImageLoader converts '%23' in src to '#' and cuts URL on '#'
225
    src = src.replace(/%23/g,'%2523');
226
    strNewHTML += "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader";
227
    strNewHTML += "(src=\'" + src + "\', sizingMethod='scale'); \"></span>" ;
228
    //myImage.outerHTML = strNewHTML;
229
    //alert(strNewHTML);
230
    return strNewHTML;
231
  }
232
}
233

    
234

    
235

    
236
/**
237
 * get the absolute position of HTML element NS4, IE4/5 & NS6, even if it's in a table.
238
 * @param element The HTML element.
239
 * @return Top left X position.
240
 */
241
function getAbsX(elt) {
242
        return (elt.x) ? elt.x : getAbsPos(elt,"Left") + 2;
243
}
244

    
245
/**
246
 * get the absolute position of HTML element NS4, IE4/5 & NS6, even if it's in a table.
247
 * @param element The HTML element.
248
 * @return Top left Y position.
249
 */
250
function getAbsY(elt) {
251
        return (elt.y) ? elt.y : getAbsPos(elt,"Top") + 2;
252
}
253

    
254
/**
255
 * TBD: Comment me.
256
 * @param elt TBD
257
 * @param which TBD
258
 */
259
function getAbsPos(elt,which) {
260
 iPos = 0;
261
 while (elt != null) {
262
        iPos += elt["offset" + which];
263
        elt = elt.offsetParent;
264
 }
265
 return iPos;
266
}
267

    
268
/**
269
 * get the absolute position of a user event (e.g., a mousedown).
270
 * @param e The user event.
271
 * @return Left or top position.
272
 */
273
function getPageX(e){
274
  var posx = 0;
275
  if (!e) var e = window.event;
276
  if (e.pageX) {
277
    posx = e.pageX;
278
  }
279
  else if (e.clientX) {
280
   posx = e.clientX;
281
  }
282
  if (document.body && document.body.scrollLeft){
283
    posx += document.body.scrollLeft;
284
  }
285
  else if (document.documentElement && document.documentElement.scrollLeft){
286
    posx += document.documentElement.scrollLeft;
287
  }
288
  return posx;
289
}
290

    
291
/**
292
 * get the absolute position of a user event (e.g., a mousedown).
293
 * @param e The user event.
294
 * @return Left or top position.
295
 */
296
function getPageY(e){
297
  var posy = 0;
298
  if (!e) var e = window.event;
299
  if (e.pageY) {
300
    posy = e.pageY;
301
  }
302
  else if (e.clientY) {
303
    posy = e.clientY;
304
  }
305
  if (document.body && document.body.scrollTop){
306
    posy += document.body.scrollTop;
307
  }
308
  else if (document.documentElement && document.documentElement.scrollTop){
309
    posy += document.documentElement.scrollTop;
310
  }
311
  return posy;
312
}
313

    
314
/**
315
 * 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. 
316
 * @return args Array of arguments passed to page, in form args[argname] = value.
317
 */
318
function getArgs(){
319
  var args = new Object();
320
  var query = location.search.substring(1);
321
  var pairs = query.split("&");
322
  for(var i = 0; i < pairs.length; i++) {
323
    var pos = pairs[i].indexOf('=');
324
    if (pos == -1) continue;
325
    var argname = pairs[i].substring(0,pos);
326
    var value = pairs[i].substring(pos+1);
327
    args[argname] = unescape(value.replace(/\+/g, " "));
328
  }
329
  return args;
330
}
331
//initialize the array once
332
window.cgiArgs = getArgs();
333

    
334
/**
335
 * convert geographic x coordinate to screen coordinate.
336
 * @param context The context object.
337
 * @param xCoord The geographic x coordinate to be converted.
338
 * @return x the converted x coordinate.
339
 */
340
function getScreenX(context, xCoord){
341
  bbox=context.getBoundingBox();
342
  width=context.getWindowWidth();
343
  bbox[0]=parseFloat(bbox[0]);
344
  bbox[2]=parseFloat(bbox[2]);
345
  var xfac = (width/(bbox[2]-bbox[0]));
346
  x=xfac*(xCoord-bbox[0]);
347
  return x;
348
}
349

    
350
/**
351
 * convert geographic y coordinate to screen coordinate.
352
 * @param context The context object.
353
 * @param yCoord The geographic x coordinate to be converted.
354
 * @return y the converted x coordinate.
355
 */
356
function getScreenY(context, yCoord){
357
  var bbox=context.getBoundingBox();
358
  var height=context.getWindowHeight();
359
  bbox[1]=parseFloat(bbox[1]);
360
  bbox[3]=parseFloat(bbox[3]);
361
  var yfac = (heighteight/(bbox[3]-bbox[1]));
362
  var y=height-(yfac*(pt.y-bbox[1]));
363
  return y;
364
}
365

    
366
/**
367
 * convert screen x coordinate to geographic coordinate.
368
 * @param context The context object.
369
 * @param xCoord The screen x coordinate to be converted.
370
 * @return x the converted x coordinate.
371
 */
372
function getGeoCoordX(context, xCooord) {
373
  var bbox=context.getBoundingBox();
374
  var width=context.getWindowWidth();
375
  bbox[0]=parseFloat(bbox[0]);
376
  bbox[2]=parseFloat(bbox[2]);
377
  var xfac = ((bbox[2]-bbox[0]) / width);
378
  var x=bbox[0] + xfac*(xCoord);
379
  return x;
380
}
381

    
382
/**
383
 * convert screen coordinate to screen coordinate.
384
 * @param context The context object.
385
 * @param yCoord The geographic y coordinate to be converted.
386
 * @return y the converted y coordinate.
387
 */
388
function getGeoCoordY(yCoord){
389
  var bbox=context.getBoundingBox();
390
  var height=context.getWindowHeight();
391
  bbox[1]=parseFloat(bbox[1]);
392
  bbox[3]=parseFloat(bbox[3]);
393
  var yfac = ((bbox[3]-bbox[1]) / height);
394
  var y=bbox[1] + yfac*(height-yCoord);
395
  return y;
396
}
397

    
398
/**
399
 * create an element and append it to the document body element.
400
 * @param type The type of element to be created.
401
 * @return node The node created and appended.
402
 */
403
function makeElt(type) {
404
  var node=document.createElement(type);
405
  document.getElementsByTagName("body").item(0).appendChild(node);
406
  return node;
407
}
408

    
409
// variable needed to determine if a popup window is currently open
410
var newWindow = '';
411
/**
412
 * open a popup window, adapted from http://www.quirksmode.org/js/croswin.html
413
 * @param url The url of the page to be opened.
414
 * @param width Width of the popup window, in pixels.
415
 * @param height Height of the popup window, in pixels.
416
 */
417
function openPopup(url, width, height) {
418
  if(width == null) {
419
    width = 300;
420
  }
421
  if(height == null) {
422
    height = 200;
423
  }
424
  if (!newWindow.closed && newWindow.location) {
425
    newWindow.location.href = url;
426
  }
427
  else {
428
    newWindow=window.open(url,'name','height=' + height + ',width=' + width);
429
    if (!newWindow.opener) newwindow.opener = self;
430
  }
431
  if (window.focus) {newWindow.focus()}
432
  return false;
433
}
434

    
435
/**
436
 * write debugging info to a textbox onscreen.
437
 * @param output String to be output.
438
 */
439
function debug(output){
440
  tarea=makeElt("textarea");
441
  tarea.setAttribute("rows","3");
442
  tarea.setAttribute("cols","40");
443
  tnode=document.createTextNode(output);
444
  tarea.appendChild(tnode);
445
}
446

    
447
/**
448
 * determine and return the target element of an event.
449
 * @param evt The event.
450
 * @return elt The element.
451
 */
452
function returnTarget(evt){
453
  evt = (evt) ? evt : ((window.event) ? window.event : "");
454
  var elt=null;
455
  if(evt.target){
456
    elt=evt.target;
457
  }
458
  else if(evt.srcElement){
459
    elt=evt.srcElement;
460
  }
461
  return elt;
462
}
463

    
464
/**
465
 * attach an event to an element.
466
 * @param elementObject The object.
467
 * @param eventName The name of the event.
468
 * @param functionObject The function to be called.
469
 */
470
function addEvent(elementObject, eventName, functionObject) {
471
  if(document.addEventListener) {
472
    elementObject.addEventListener(eventName, functionObject, false);
473
  }
474
  else if(document.attachEvent) {
475
    elementObject.attachEvent("on" + eventName, functionObject);
476
  }
477
}
478

    
479
/**
480
 * handle event attached to an object.
481
 * @param evt The event.
482
 */
483
function handleEventWithObject(evt){
484
  var elt = returnTarget(evt);
485
  var obj = elt.ownerObj;
486
  if (obj!=null) obj.handleEvent(evt);
487
}
488

    
(3-3/3)