Source: bemap.js

/**
 * BeNomad BeMap JavaScript API
 * @projectname BeNomad BeMap JavaScript API
 */

var bemap = bemap || {};

bemap.version = '1.0.0';

/**
 * Extends the class declaration with the parent class.
 * @param {Class} child
 * @param {Class} parent
 */
bemap.inherits = function(child, parent) {
  child.prototype = Object.create(parent.prototype);
  child.prototype.constructor = child;
};

/**
 * Test if the object is inherits of the class (type).
 * @param {Object} obj The object.
 * @param {Class} type The inherits class model.
 * @return {boolean}
 */
bemap.inheritsof = function(obj, type) {
  // return obj.prototype.isPrototypeOf(type);
  return (obj instanceof type);
};

/**
 * Fill all fields of target object with source object.
 * Only the feilds of target class model are filled.
 * @param {Object} source Source object.
 * @param {Object} target Target object.
 */
bemap.fillFields = function(source, target) {
  for (var key in target) {
    var value = source[key];
    if (value) {
      target[key] = value;
    }
  }
};

/**
 * Get absolute path of current script.
 * @return {String} Retun absolute path of current script.
 */
bemap._getCurrentPath_cache = null;
bemap.getCurrentPath = function() {
  if (bemap._getCurrentPath_cache === null) {
    var scripts = document.getElementsByTagName('script');
    var path = scripts[scripts.length - 1].src.split('?')[0];
    bemap._getCurrentPath_cache = path.split('/').slice(0, -1).join('/') + '/';
  }
  return bemap._getCurrentPath_cache;
};

/**
 * Perform a Ajax request.
 * @param {String} method HTTP method (GET, POST).
 * @param {String} url URL of request.
 * @param {String|Object} data POST data of request, can by a string or javascript object. The javascript object will be converted in JSON string.
 * @param {String} success Callback if the request is executed with success.
 * @param {String} faild Callback if the request was failled.
 * @param {Object
}
options Options object.*@param {
    Object} options.headers List of HTTP headers.
 * @param {Object} options.requestFormat mime type of predefined value, json, xml or urlencoded.
 */
bemap.ajax = function(method, url, data, success, failled, options) {
  var opt = options || {};
  var xhr = new XMLHttpRequest();
  var called = false;

  xhr.open(method, url, true);

  if(data instanceof Object) {
    data = JSON.stringify(data);
    if(!opt.requestFormat) {
      opt.requestFormat = "json";
    }
  }

  if(opt.requestFormat) {
    if(!opt.headers) {
      opt.headers = [];
    }

    if(opt.requestFormat == 'json') {
      opt.headers.push({"key": "Content-Type", "value": "application/json"});
    } else if(opt.requestFormat == 'xml') {
      opt.headers.push({"key": "Content-Type", "value": "text/xml"});
    } else if(opt.requestFormat == 'urlencoded') {
      opt.headers.push({"key": "Content-Type", "value": "application/x-www-form-urlencoded"});
    } else {
      opt.headers.push({"key": "Content-Type", "value": opt.requestFormat});
    }
  }

  if(opt.headers) {
    for(var i = 0; i < opt.headers.length; i++) {
      var header = opt.headers[i];
      xhr.setRequestHeader (header.key, header.value);
    }
  }

  xhr.onreadystatechange = function() {
    if (!called && (!this.readyState || xhr.readyState === 4 || this.readyState === 'complete' || this.readyState === 'loaded')) {
      called = true;
      var doc = xhr.response || xhr.responseText || xhr.responseXML;
      if (xhr.status == 200) {
        success(xhr, doc);
      } else {
        if (typeof(failled) === 'function') {
          failled(xhr, doc);
        }
        console.error("Status " + xhr.status, url);
      }
    }
  };

  xhr.send(data);
};

/**
 * Load a JavaScript file.
 * @param {String} src Script name with path.
 * @param {Object} options
 */
bemap._require_cache = [];
bemap.require = function(src, options) {
  var key, inCacheSrc, found = false;

  for (key in bemap._require_cache) {
    inCacheSrc = bemap._require_cache[key];
    if (inCacheSrc == src) {
      found = true;
    }
  }

  if (!found) {
    var head = document.head || document.getElementsByTagName('HEAD').item(0) || document.documentElement;
    var tag = document.createElement('script');

    if (!head || !tag) {
      console.error("Unsupport browser!");
    }

    tag.type = 'text/javascript';
    if (src.charAt(0) == '/') {
      tag.src = src;
    } else {
      tag.src = this.getCurrentPath() + src;
    }

    var opt = options || {};
    if (typeof(opt.success) === 'function') {
      var called = false;
      tag.onload = tag.onreadystatechange = function() {
        if (!called && (!this.readyState || xhr.readyState === 4 || this.readyState === 'complete' || this.readyState === 'loaded')) {
          called = true;
          if (xhr.Status == 200) {
            opt.success(xhr, doc);
          } else {
            if (typeof(opt.faild) === 'function') {
              faild(xhr, doc);
            }
          }
        }
      };
    }

    tag.onerror = function() {
      console.error("Cannont load the library '" + src + "'");
    };

    head.appendChild(tag);
    bemap._require_cache.push(src);
  }
};

/**
 * @classdesc
 * Base class for Exception.
 *
 * @constructor
 * @param {String} message.
 * @param {bemap.Exception} cause.
 */
bemap.Exception = function(message, cause) {
  this.message = message;
  this.cause = cause ? cause : null;
};

/**
 * Return the message of exception.
 * @return {String} Return the message of exception.
 */
bemap.Exception.prototype.getMessage = function() {
  return this.message;
};

/**
 * Return the cause of exception.
 * @return {bemap.Exception} Return the cause of exception.
 */
bemap.Exception.prototype.getCause = function() {
  return this.cause;
};

/**
 * Return stack of exceptions.
 * @return {String} Return stack of exceptions.
 */
bemap.Exception.prototype.getStack = function() {
  var exception = this,
    stack = "";
  while (true) {
    stack = exception.message + "\n";
    if (exception.cause === null) {
      break;
    } else {
      exception = exception.cause;
    }
  }
  return stack;
};

/**
 * Print stack of exceptions.
 * @return {String} Print stack of exceptions.
 */
bemap.Exception.prototype.printStack = function() {
  console.error(this.getStack());
};

/**
 * @classdesc
 * Base class for Context.
 *
 * @constructor
 * @param {object} options.
 */
bemap.Context = function(options) {
  var opts = options || {};

  /**
   * Define the protocol used. The HTTP or HTTPS, by default the HTTP.
   * @protected
   * @type {string}
   */
  this.protocol = opts.secure ? 'https' : 'http';

  /**
   * Define the host name of BeMap server. By default "bemap-beta.benomad.com".
   * @protected
   * @type {string}
   */
  this.host = opts.host || 'bemap-beta.benomad.com';

  /**
   * Define the path of bgis context. The string must be start with / character. By default "/bgis/".
   * @protected
   * @type {string}
   */
  this.path = opts.path || '/bgis/';

  /**
   * Define the login.
   * @protected
   * @type {string}
   */
  this.login = opts.login;

  /**
   * Define the Password.
   * @protected
   * @type {string}
   */
  this.password = opts.password;

  /**
   * Heap cache of full URL to BeMap context.
   * @private
   * @type {string}
   */
  this.cacheBaseUrl = null;

  /**
   * Heap cache of base 64 authentication.
   * @private
   * @type {string}
   */
  this.cacheAuth = null;

  /**
   * Set the authentication parameters in POST data of request.
   * @private
   * @type {boolean}
   */
  this.authInPost = opts.authInPost ? true : false;

  /**
   * The default BeMap Geoserver
   * @private
   * @type {string}
   */
  this.geoserver = opts.geoserver ? opts.geoserver : undefined;
};

/**
 * Return the BaMap URL.
 * @return {String} BeMap URL
 */
bemap.Context.prototype.getBaseUrl = function() {
  if (!this.cacheBaseUrl) {
    this.cacheBaseUrl = this.protocol + "://" + this.host + this.path;
  }
  return this.cacheBaseUrl;
};

/**
 * Return the BaMap Authentication.
 * @return {String} BeMap URL
 */
bemap.Context.prototype.getAuthUrlParams = function() {
  if (this.login && this.password && !this.cacheAuth) {
    this.cacheAuth = "appid=" + this.login + "&appcode=" + this.password;
  }
  return this.cacheAuth;
};

/**
 * Set to true if the authentication parameters will be write in the POST data of request.
 */
bemap.Context.prototype.setAuthInPost = function(authInPost) {
  this.authInPost = authInPost;
};

/**
 * Return true if the authentication parameters will be write in the POST data of request.
 * @return {boolean} true if the authentication parameters will be write in the POST data of request..
 */
bemap.Context.prototype.isAuthInPost = function() {
  return this.authInPost;
};

/**
 * Return the default BaMap Geoserver of context.
 * @return {String} BeMap Geoserver
 */
bemap.Context.prototype.getGeoserver = function() {
  return this.geoserver;
};

/**
 * Perform a HTTP Post request.
 * @param {Object} options
 */
bemap.Context.prototype.post = function(options) {
  var opt = options || {};
  return this;
};