Project

General

Profile

1
/*
2
License: LGPL as per: http://www.gnu.org/copyleft/lesser.html
3
$Id: Mapbuilder.js 3819 2008-02-01 00:31:29Z ahocevar $
4
*/
5

    
6
/** get a time stamp at start of the page load */
7
var mbTimerStart = new Date();
8

    
9
/** the global config object */
10
var config;
11

    
12
if( typeof baseDir == "undefined") {
13
/** URL of Mapbuilder's lib/ directory. */
14
var baseDir;
15
}
16

    
17
/** mapbuilder environement settings, defaults to a .xml extension but is 
18
  auto-configured by the ant build script to .jsp for tomcat environment 
19
  the URL to this file will be pre-pended with the baseDir value.
20
*/
21
var mbServerConfig = "mapbuilderConfig.xml";
22
var mbNsUrl = "http://mapbuilder.sourceforge.net/mapbuilder";
23

    
24
// LoadState Constants
25
var MB_UNLOADED=0;    // Scripts not loaded yet
26
var MB_LOAD_CORE=1;   // Loading scripts loaded defined in Mapbuilder
27
var MB_LOAD_CONFIG=2; // Loading scripts loaded defined in Config
28
var MB_LOADED=3;      // All scripts loaded
29

    
30
/**
31
 * This Object bootstraps the Mapbuilder libraries by loading the core
32
 * script files.
33
 * When Config.js is loaded, the script files for objects described in the
34
 * Mapbuilder config file are loaded.
35
 * Objects which have dependencies will trigger the dependancies to load
36
 * when they are loaded.
37
 *
38
 * @constructor
39
 * @author Cameron Shorter
40
 * @requires Config
41
 * @requires Listener
42
 * @requires ModelBase
43
 * @requires Sarissa
44
 * @requires Util
45
 */
46
function Mapbuilder() {
47

    
48
  /**
49
   * Determines which Mapbuilder scripts are loading.
50
   * TBD: Is it possible to use enumerated types in JS?
51
   */
52
  this.loadState=MB_UNLOADED;
53

    
54
  /** Array of objects that are loading.  Don't continue initialisation until
55
   * all objects have loaded. */
56
  this.loadingScripts=new Array();
57
  
58
  /** Array of scripts that have to be loaded ordered */
59
  this.orderedScripts = new Array();
60
  
61
  /** Timer to load ordered scripts */
62
  this.scriptLoader = null;
63

    
64
  /** Timer to periodically check if scripts have loaded. */
65
  this.scriptsTimer=null;
66

    
67
  /**
68
   * Called periodically and moves onto the next loadState when this round of
69
   * scripts have loaded.
70
   * For IE clients, object.readyState is used to check if scripts are loaded.
71
   * Mozilla works fine without this function - I think it is single threaded.
72
   */
73
  this.checkScriptsLoaded=function() {
74
    if (document.readyState!=null){
75
      // IE client
76

    
77
      // Scripts are removed from array when they have loaded
78
      while(this.loadingScripts.length>0
79
        &&(this.loadingScripts[0].readyState=="loaded"
80
          ||this.loadingScripts[0].readyState=="complete"
81
          ||this.loadingScripts[0].readyState==null))
82
      {
83
        this.loadingScripts.shift();
84
      }
85
      if (this.loadingScripts.length==0 && this.orderedScripts.length == 0){
86
        this.setLoadState(this.loadState+1);
87
      }
88
    }
89
    else{
90
      // Mozilla client
91
      if(this.loadState==MB_LOAD_CORE && config!=null){
92
        // Config has finished loading
93
        this.setLoadState(MB_LOAD_CONFIG);
94
      }
95
    }
96
  }
97

    
98
  /**
99
   * Move onto loading the next set of scripts.
100
   * @param newState The new loading state.
101
   */
102
  this.setLoadState=function(newState){
103
    this.loadState=newState;
104
    switch (newState){
105
      case MB_LOAD_CORE:
106
        // core scripts have to be loaded in the correct order (needed for IE)
107
        this.loadOrdered = true;
108
        this.loadScript(baseDir+"/util/openlayers/OpenLayers.js");
109
        this.loadScript(baseDir+"/util/sarissa/Sarissa.js");
110
        this.loadScript(baseDir+"/util/sarissa/javeline_xpath.js");
111
        this.loadScript(baseDir+"/util/sarissa/javeline_xslt.js");
112
        this.loadScript(baseDir+"/util/sarissa/sarissa_dhtml.js");
113
        this.loadScript(baseDir+"/util/sarissa/sarissa_ieemu_xpath.js");
114
        //this.loadScript(baseDir+"/util/sarissa/sarissa_ieemu_xslt.js");//all deprecated
115
        this.loadScript(baseDir+"/util/proj4js/proj4js-compressed.js");
116
        this.loadScript(baseDir+"/util/Util.js");
117
        this.loadScript(baseDir+"/util/Listener.js");
118
        this.loadScript(baseDir+"/model/ModelBase.js");
119
        this.loadScript(baseDir+"/model/Config.js");
120
        // from now on, scripts can be loaded in any order
121
        this.loadOrdered = false;
122
        break;
123
      case MB_LOAD_CONFIG:
124
        if(document.readyState){
125
          // IE
126
          config=new Config(mbConfigUrl);
127
          config.loadConfigScripts();
128
        }else{
129
          // Mozilla
130
          this.setLoadState(MB_LOADED);
131
        }
132
        break;
133
      case MB_LOADED:
134
        window.clearInterval(this.scriptsTimer);
135
        break;
136
    }
137
  }
138

    
139
  /**
140
   * Dynamically load a script file if it has not already been loaded.
141
   * @param url The url of the script.
142
   * that loadScript was called
143
   */
144
  this.loadScript=function(url){
145
    // if we are working with a compressed build, load only scripts that
146
    // are not part of the compressed build. This check is done by looking
147
    // into the global namespace for a function that has the same name as
148
    // the script file (without path and without .js). Because script files
149
    // in the util dir do not follow that pattern, exclude them from the
150
    // check separately.
151
    if(typeof MapBuilder_Release == "boolean") {
152
      if (url.indexOf(baseDir+"/util/") != -1) {
153
        return;
154
      }
155
      var urlElements = url.split("/");
156
      var scriptClass = urlElements[urlElements.length-1].replace(/.js$/, "");
157
      if(typeof window[scriptClass] == "function") {
158
        return;
159
      }
160
    }
161

    
162
    if(!document.getElementById(url)){
163
      var script = document.createElement('script');
164
      script.src = url;
165
      script.id = url;
166
      script.defer = false;   //not sure of effect of this?
167
      script.type = "text/javascript";
168
      if (document.readyState && this.loadOrdered == true) {
169
        // in IE, mark the script as ordered
170
        this.orderedScripts.push(script);
171
        if (!this.scriptLoader) {
172
          this.scriptLoader = window.setInterval('mapbuilder.loadNextScript()', 50);
173
        }
174
      } else {
175
        // add to dom tree, except if we are using IE and want to load ordered
176
        document.getElementsByTagName('head')[0].appendChild(script);
177
      }
178
      if (document.readyState) {
179
        // this is only needed for IE
180
        this.loadingScripts.push(script);
181
      }
182
    }
183
  }
184
   
185
  /**
186
   * loads one script after another - only for IE. This function is run in a
187
   * 50ms interval and clears its interval if there are no more scripts to
188
   * load. It actually loads the first script from the orderedScripts array.
189
   */
190
  this.loadNextScript = function() {
191
    if (this.orderedScripts.length == 0) {
192
      window.clearInterval(this.scriptLoader);
193
      this.scriptLoader = null;
194
    } else {
195
      var script = this.orderedScripts[0];
196
      if (!script.loading) {
197
        script.loading = true;
198
        this.doLoadScript(script);
199
      }
200
    }
201
  }
202
  
203
  /**
204
   * starts script loading by adding the script node to the dom tree - IE only.
205
   * This function adds a readyState handler to the script node.
206
   */
207
  this.doLoadScript = function(script) {
208
    var objRef = this;
209
    script.onreadystatechange = function(){objRef.checkScriptState(this)};
210
    document.getElementsByTagName('head')[0].appendChild(script);
211
  }
212
  
213
  /**
214
   * readyState handler for scripts - IE only. This will remove the script from
215
   * the array of scripts that have still to be loaded.
216
   */
217
  this.checkScriptState = function(script) {
218
    if (script.readyState == "loaded" || script.readyState == "complete") {
219
      for (var i=0; i<this.orderedScripts.length; i++) {
220
        if (script == this.orderedScripts[i]) {
221
          this.orderedScripts.splice(i, 1);
222
          break;
223
        }
224
      }
225
    }
226
  }
227

    
228
  /**
229
   * Internal function to load scripts for components that don't have <scriptfile>
230
   * specified in the config file.
231
   * @param xPath Xpath match of components from the Config file.
232
   * @param dir The directory the script is located in.
233
   */
234
  this.loadScriptsFromXpath=function(nodes,dir) {
235
    //var nodes = this.doc.selectNodes(xPath);
236
    for (var i=0; i<nodes.length; i++) {
237
      if (nodes[i].selectSingleNode("mb:scriptFile")==null){
238
        scriptFile = baseDir+"/"+dir+nodes[i].nodeName+".js";
239
        this.loadScript(scriptFile);
240
      }
241
    }
242
  }
243

    
244
  //derive the baseDir value by looking for the script tag that loaded this file
245
  if (!baseDir) {
246
    var head = document.getElementsByTagName('head')[0];
247
    var nodes = head.childNodes;
248
    for (var i=0; i<nodes.length; ++i ){
249
      var src = nodes.item(i).src;
250
      if (src) {
251
        //var index = src.indexOf("/Mapbuilder.js");
252
        // Modified so it will work with original or compressed file
253
        var index = src.indexOf("/Mapbuilder.js");
254
        if (index>=0) {
255
          baseDir = src.substring(0, index);
256
        } else {
257
          index = src.indexOf("/MapbuilderCompressed.js");
258
          if (index>=0) {
259
            baseDir = src.substring(0, index);
260
          }
261
        }
262
      }
263
    }
264
  }
265

    
266
  // Start loading core scripts.
267
  this.setLoadState(MB_LOAD_CORE);
268

    
269
  // Start a timer which periodically calls checkScriptsLoaded().
270
  this.scriptsTimer=window.setInterval('mapbuilder.checkScriptsLoaded()',100);
271
}
272

    
273
/**
274
 * copied from sarissa, a function to check browser security setting in IE, 
275
 * opens a help page if ActiveX objects are disabled.
276
 */
277
function checkIESecurity()
278
{
279
  var testPrefixes = ["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"];
280
  // found progID flag
281
  var bFound = false;
282
  for(var i=0; i < testPrefixes.length && !bFound; i++) {
283
    try {
284
      var oDoc = new ActiveXObject(testPrefixes[i]);
285
      bFound = true;
286
    }
287
    catch (e) {
288
      //trap; try next progID
289
    }
290
  }
291
  if (!bFound) window.open("/mapbuilder/docs/help/IESetup.html");  //TBD: set this URL in config
292
}
293

    
294
if (navigator.userAgent.toLowerCase().indexOf("msie") > -1) checkIESecurity();
295
var mapbuilder=new Mapbuilder();
296

    
297
/**
298
 * Initialise Mapbuilder if script has been loaded, else wait to be called
299
 * again.
300
 */
301
function mapbuilderInit(){
302
  if(mapbuilder && mapbuilder.loadState==MB_LOADED){
303
    window.clearInterval(mbTimerId);
304
    config.parseConfig(config);
305
    if (Proj4js) {
306
      Proj4js.libPath = baseDir+"/util/proj4js/";
307
      Proj4js.proxyScript = config.proxyUrl+'?url=';
308
    }
309
    config.callListeners("init");
310
    var mbTimerStop = new Date();
311
    //alert("load time:"+(mbTimerStop.getTime()-mbTimerStart.getTime()) );
312
    if (window.mbInit) window.mbInit();
313
    config.callListeners("loadModel");
314
  }
315
}
316

    
317
/** Timer used when checking if scripts have loaded. */
318
var mbTimerId;
319

    
320
/**
321
 * Mapbuilder's main initialisation script.
322
 * This should be called from the main html file using:
323
 *   <body onload="mbDoLoad()">
324
 * @param initFunction Optional - A function reference that will be called after 
325
 * config.init() has been called.  This is to give application code a chance to
326
 * do initialization and be guaranteed that all objects exist (inlcuding config).
327
 */
328
function mbDoLoad(initFunction) {
329
  // See if scripts have been loaded every 100msecs, then call config.init().
330
  mbTimerId=window.setInterval('mapbuilderInit()',100);
331
  if (initFunction) window.mbInit = initFunction;
332
}
(2-2/6)