Gapminder/vizabi

View on GitHub
src/base/class.js

Summary

Maintainability
B
4 hrs
Test Coverage
import { forEach, warn } from "base/utils";

let initializing = false;
const fnTest = /xyz/.test(() => {
  let xyz;
}) ? /\b_super\b/ : /.*/;

function extend(name, extensions) {

  //in case there are two args
  extensions = arguments.length === 1 ? name : extensions;
  const _super = this.prototype;
  initializing = true;
  const prototype = new this();
  initializing = false;

  forEach(extensions, (method, name) => {
    if (typeof extensions[name] === "function" && typeof _super[name] === "function" && fnTest.test(extensions[name])) {
      prototype[name] = (function(name, fn) {
        return function() {
          const tmp = this._super;
          this._super = _super[name];
          const ret = fn.apply(this, arguments);
          this._super = tmp;
          return ret;
        };
      })(name, extensions[name]);
    } else {
      prototype[name] = method;
    }
  });

  function Class() {
    if (this.trackInstances)
      Class.instances.push(this);
    if (!initializing && this.init) {
      this.init(...arguments);
    }
  }

  // Populate our constructed prototype object
  Class.prototype = prototype;
  Class.prototype.constructor = Class;
  Class.extend = extend;

  Class._collection = {};
  Class.instances = [];
  Class.register = function(name, code) {
    if (typeof this._collection[name] !== "undefined") {
      warn('"' + name + '" is already registered. Overwriting...');
    }
    this._collection[name] = code;
  };

  Class.unregister = function(name) {
    this._collection[name] = void 0;
  };

  Class.getCollection = function() {
    return this._collection;
  };

  //define a method or field in this prototype
  Class.define = function(name, value) {
    this.prototype[name] = value;
  };

  //get an item of the collection from this class
  Class.get = function(name, silent) {
    if (this._collection.hasOwnProperty(name)) {
      return this._collection[name];
    }
    if (!silent) {
      warn('"' + name + '" was not found.');
    }
    return false;
  };
  //register extension by name
  if (arguments.length > 1 && this.register) {
    this.register(name, Class);
  }
  return Class;
}

const Class = function() {};
Class.extend = extend;

export default Class;