docs: function(name, container, args, events) {
        /* handling for any default values if args are not specified */
        var mergeDefaults = function(args, defaults) {
          var args = args || {};
  
          if (typeof defaults == 'object') {
            for (var key in defaults) {
              if (elation.utils.isNull(args[key])) {
                args[key] = defaults[key];
              }
            }
          }
          
          return args;
        };
  
        var realname = name;
        if (elation.utils.isObject(name)) {
          // Simple syntax just takes an object with all arguments
          args = name;
          realname = elation.utils.any(args.id, args.name, null);
          container = (!elation.utils.isNull(args.container) ? args.container : null);
          events = (!elation.utils.isNull(args.events) ? args.events : null);
        }
  
        // If no args were passed in, we're probably being used as the base for another 
        // component's prototype, so there's no need to go through full init
        if (elation.utils.isNull(realname) && !container && !args) {
          var obj = new component.base(type);
          
          // apply default args
          obj.args = mergeDefaults(obj.args, elation.utils.clone(obj.defaults));
          
          return obj;
        }
  
        // If no name was passed, use the current object count as a name instead ("anonymous" components)
        if (elation.utils.isNull(realname) || realname === "") {
          realname = component.objcount;
        }
  
        if (!component.obj[realname] && !elation.utils.isEmpty(args)) {
          component.obj[realname] = obj = new component.base(type);
          component.objcount++;
        //}
        // TODO - I think combining this logic would let us use components without needing HTML elements for the container
        //if (component.obj[realname] && container !== undefined) {
          component.obj[realname].componentinit(type, realname, container, args, events);
  
  /*
          if (component.extendclass) {
            component.obj[realname].initSuperClass(component.extendclass);
          }
  */
          // fix handling for append component infinite recursion issue
          if (args.append instanceof elation.component.base) 
            args.append = args.append.container;
  
          if (args.before instanceof elation.component.base) 
            args.before = args.before.container;
  
          // apply default args
          try {
            if (typeof obj.defaults == 'object')
              args = mergeDefaults(args, elation.utils.clone(obj.defaults));
  
            var parentclass = component.extendclass;
  
            // recursively apply inherited defaults
            while (parentclass) {
              if (typeof parentclass.defaults == 'object')
                elation.utils.merge(mergeDefaults(args, elation.utils.clone(parentclass.defaults)),args);
  
              parentclass = parentclass.extendclass;
            }
          } catch (e) {
            console.log('-!- Error merging component args', e.msg);
          }
  
          if (typeof obj.init == 'function') {
            obj.init(realname, container, args, events);
          }
        }
        return component.obj[realname];
      }