Source: wk.js

/*jslint plusplus: true, white: true, indent: 2, maxlen: 90 */
/**
 *  @author    Wolfgang Kowarschick
 *  @copyright 2013, Wolfgang Kowarschick
 *  <br/>
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted under the terms of the 
 *  Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported    
 *  (CC BY-NC-SA 3.0: http://creativecommons.org/licenses/by-nc-sa/3.0/). 
 */

/**
 *  The sandbox pattern: When this function is evaluated,
 *  it first loads all modules stated in <code>p_modules</code>
 *  and then calls the callback function 
 *  <pre>function(p_env_1, ... p_env_n)
 *{ // code running in a sandbox 
 *}</pre>
 *  which has to be passed as last argument,
 *
 *  @see Stoyan Stefanov, JavaScript Patterns. O'Reilly, 2010
 * 
 *  @property WAIT_UNTIL_READY   - A dummy argument for <code>$wk<$code> calls. 
 *                                 When it is passed the sandbox is not executed 
 *                                 before the HTML document has been loaded 
 *                                 completely.
 *  @property WAIT_UNTIL_COMPLETE - A dummy argument for <code>$wk<$code> calls. 
 *                                  When it is passed the sandbox is not executed 
 *                                  before the HTML document and all 
 *                                  its subdocuments (images etc.) have been 
 *                                  loaded completely.
 *  @function
 *  @global
 *  @name $wk$­
 *  
 *  @param {Object[]} arguments  
 *    A list of JSON file names (strings) and/or arbitrary objects.
 *    Each JSON file is loaded and its content is passed to the sandbox 
 *    function. Every other content object is directly passed to the callback
 *    function. 
 *  @param {Function} p_sandbox      
 *    As last argument the sandbox, a callback function, has to be passed: 
 *    <code>function(p_env_1, ... p_env_n){ ...}</code>
 *    The environment parameter <code>p_env_1</code>, ..., <code>p_env_n</code>
 *    contain the <code>objects</code> created or passed by <code>$wk$</code>.
 *    So the number of arguments should be equal to
 *    <code>arguments.length-1</code> 
 */
(function(p_root, document, XMLHttpRequest)
{ "use strict"; 

////////////////////////////////////////////////////////////////////////////////
// $wk$ library: utilities
////////////////////////////////////////////////////////////////////////////////

var l_wk, l_key = null;

/**
 *  An object created by calling <code>$new$(Class, [1, 2, 3])</code> 
 *  is identical to an object created with <code>new Class(1, 2, 3)</code>.
 *  
 *  @method
 *  @name $wk$.$new$
 *  
 *  @param {Function} p_constructor A function to be used as constructor.
 *  @param {Array}    p_arguments   An array of arguments to be passed
 *                                  to the constructor
 *  @returns {Object} The newly constructed object.
 *  @see http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
 */

function f_new(p_constructor, p_arguments) 
{ function F_C() 
  { return p_constructor.apply(this, p_arguments); }
  F_C.prototype = p_constructor.prototype;
  return new F_C();
}

/**
 *  Creates a chain of nested objects.
 *  <p>
 *  For instance: The following function call
 *  <pre>  $wk$.pkg("ldvcs.view");</pre>
 *  results in the creation of two objects (if they do not already exist):
 *  <pre>
 *   ldvcs
 *   ldvcs.view</pre>
 *  </p>
 *  
 *  @method
 *  @name $wk$.pkg
 *  
 *  @param {String} p_name  A package name, i.e. one or more name literals
 *                          separated by dots.
 *  @param {String} [p_create = true]   
 *                          Indicates, whether or not to create the package,
 *                          if it does not exists
 *  @returns {Object}       The last package object of the package 
 *                          object chain.
 */
function f_pkg(p_name)
{ var i, n,
      l_subpackages    = p_name.split("."),  // all literal names
      l_name,
      l_subpackage_object,
      l_package_object = p_root;             // the root object
  
  for (i = 0, n = l_subpackages.length; i < n; i++) // for each literal name
  { l_name   = l_subpackages[i];  // the current literal name

    // Fetch the associated package object.
    l_subpackage_object = l_package_object[l_name];
 
    // If it does not exist: create it.
    if (!l_subpackage_object)
    { l_package_object[l_name] = l_subpackage_object = {}; }
    
    // Set the current subpackage object to be the new package object,
    // for which the next subpackage object hast to be created.
    l_package_object = l_subpackage_object;
  } 
  
  return l_package_object;
}

/**
  *  Recursively mixes properties of a source object into a target object.
  *  Overridable properties are overridden, others not.  
  *  
  *  @method
  *  @name $wk$.mixin
  *  
  *  @param {Object|String} p_target An arbitrary object.
  *  @param {Object|String} p_source 
  *         Another arbitrary object (or a path name of an object) 
  *         the properties of which are to be recursively mixed into 
  *         <code>p_target</code>.
  */
function f_mixin(p_source, p_target)
{ var l_key = null, 
      l_target;

  p_source = (p_source && p_source.constructor === String) 
               ? f_pkg(p_source, false) 
               : p_source;
  p_target = (p_target.constructor === String)
               ? f_pkg(p_target, false)
               : p_target;
  
  if (p_source === p_target)
  { return; }

  for (l_key in p_source)
  { if (p_source.hasOwnProperty(l_key))
    { l_target = p_target[l_key];
      if (   l_target && l_target instanceof Object 
          && !(l_target instanceof Function)
         )
      { f_mixin(p_source[l_key], l_target); }
      else 
      { Object.defineProperty
          (p_target, l_key, Object.getOwnPropertyDescriptor(p_source, l_key));
      }
    }
  }
}

l_wk =
function WK()
{ // Ensure that the function is called as a constructor.
  if (!(this instanceof WK))
  { return f_new(WK, arguments); }
  
  var  i, j,
       n              = arguments.length-1,
       f_callback     = arguments[n], 
       l_arguments    = [],
       l_arg,
       l_waiting_for  = 1;
  
  function f_callback_if_ready()
  { l_waiting_for--;
    if (l_waiting_for === 0)
    { f_callback.apply({}, l_arguments); }
  }
  
  // Load the JSON file p_url and store the result at l_arguments[p_pos].
  function f_load(p_url, p_pos)
  { var l_xhr = new XMLHttpRequest();
    
    l_waiting_for++;
    l_xhr.onload  = function()
                    { l_arguments[p_pos] = JSON.parse(this.response);
                       f_callback_if_ready();
                    };
    l_xhr.onerror = function()
                    { throw new Error(p_url + " not found"); }; 
    l_xhr.overrideMimeType("application/json");  
    l_xhr.open("GET", p_url, true);
    l_xhr.send();
  }
  
  for (i = 0, j = 0; i < n; i++)
  { l_arg = arguments[i];
  
    if (l_arg === WK.WAIT_UNTIL_READY)
    { if (document.readyState === "loading")
      { l_waiting_for++;
        document.addEventListener("DOMContentLoaded", f_callback_if_ready, false);
      }
    }
    else if (l_arg === WK.WAIT_UNTIL_COMPLETE)
    { if (document.readyState !== "complete")
      { l_waiting_for++;
        p_root.addEventListener("load", f_callback_if_ready);
      }
    }
    else if (l_arg.constructor === String)
    { f_load(l_arg, j);  j++; }
    else
    { l_arguments[j] = l_arg; j++; } 
  }

  f_callback_if_ready();
};

l_wk.WAIT_UNTIL_READY    = {};
l_wk.WAIT_UNTIL_COMPLETE = {};
l_wk.prototype           = l_wk;
l_wk.$new$               = f_new;
l_wk.pkg                 = f_pkg;
l_wk.mixin               = f_mixin;

/*jslint forin: true*/
for (l_key in l_wk)
{ Object.defineProperty(l_wk, l_key, {writable: false, configurable: false}); }

Object.defineProperty
  (p_root, "$wk$", { value: l_wk, writable: false, configurable: false });

////////////////////////////////////////////////////////////////////////////////
// End of $wk$ Library
////////////////////////////////////////////////////////////////////////////////
}(this, this.document, this.XMLHttpRequest)); 
W. Kowarschick © 2013 (CC BY-NC-SA 3.0: http://creativecommons.org/licenses/by-nc-sa/3.0/)
Documentation generated by JSDoc 3.3.0-dev on Thu Nov 14 2013 13:33:07 GMT+0100 (MEZ) using the DocStrap template.