UNPKG

glass-platform

Version:

Glass platform

501 lines (454 loc) 15.2 kB
// Generated by CoffeeScript 1.6.2 (function() { var Component, assert, dispose, extend, generateId, getBaseDefiningClass, getUnderrideName, glass_Component, initialize, isPrimitive, properties, underride, __slice = [].slice; require('./global'); generateId = function(parent, type) { var count, counts, name, _ref, _ref1; name = type.name; if (name == null) { throw new Error("type did not have a name: " + type); } counts = (_ref = parent._Component_generateId_counts) != null ? _ref : parent._Component_generateId_counts = {}; count = (_ref1 = counts[name]) != null ? _ref1 : counts[name] = 0; count++; counts[name] = count; return "" + name + "_" + count; }; module.exports = Component = glass_Component = (function() { function glass_Component(properties) { this.initialize(properties); this; } return glass_Component; })(); isPrimitive = function(object) { return Object.isNumber(object) || Object.isBoolean(object) || Object.isString(object); }; Component.normalizeProperties = function(properties, definingClass) { var name, property, _base, _base1, _ref, _ref1, _ref2, _ref3; if (properties == null) { properties = {}; } for (name in properties) { property = properties[name]; if (Object.isFunction(property)) { property = { writable: false, value: property }; } else if ((property == null) || isPrimitive(property) || Object.isArray(property)) { property = { value: property }; } if ((property.get == null) && (property.set == null) && !property.hasOwnProperty('value')) { property.value = null; } if (property.hasOwnProperty('value')) { if ((_ref = property.writable) == null) { property.writable = true; } } if (Object.isFunction(property.value)) { if ((_ref1 = (_base = property.value).id) == null) { _base.id = name; } } if (definingClass != null) { if ((_ref2 = property.definingClass) == null) { property.definingClass = definingClass; } if (Object.isFunction(property.value)) { if ((_ref3 = (_base1 = property.value).definingClass) == null) { _base1.definingClass = definingClass; } } } properties[name] = property; } return properties; }; Component.defineProperties = function(object, properties, definingClass) { properties = Component.normalizeProperties(properties, definingClass); Object.defineProperties(object, properties); return properties; }; Component.disposeProperties = function(object) { var key, value; for (key in object) { value = object[key]; if ((value != null) && value.parent === object && Object.isFunction(value.dispose)) { value.dispose(); } } }; Component.id = "glass.Component"; Component.toString = function() { return this.id; }; Component.valueOf = function() { var _ref; return (_ref = this.value) != null ? _ref : this.id; }; properties = { id: { get: function() { return this._id; }, set: function(value) { if (this._id != null) { throw new Error("id has already been set to " + this._id); } return this._id = value; } }, parent: { get: function() { return this._parent; }, set: function(value) { if (this._parent != null) { throw new Error("parent has already been set to " + this._parent); } return this._parent = value; } }, inner: { description: "Calls the subclass defined function if present.", value: function() { var args, fn, innerName, _ref, _ref1; fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; innerName = (_ref = fn.innerName) != null ? _ref : fn.innerName = getUnderrideName(fn.definingClass, fn.id); return (_ref1 = this[innerName]) != null ? _ref1.apply(this, args) : void 0; } }, initialize: initialize = function(properties) { var id, key, parent, value, _ref; if (properties == null) { throw new Error("properties object is required " + properties); } if (properties.parent == null) { throw new Error("parent is required"); } parent = properties.parent; id = (_ref = properties.id) != null ? _ref : properties.id = generateId(parent, this.constructor); parent[id] = this; for (key in properties) { value = properties[key]; this[key] = value; } return this.inner(initialize); }, dispose: dispose = function() { if (this._parent != null) { Component.disposeProperties(this); if (this._parent === global) { delete this._parent[this.id]; } else { this._parent[this.id] = null; } this._parent = null; this.inner(dispose); } }, disposed: { get: function() { return this._parent === null; } }, get: function(id, parsed) { var colon, factory, isClass, throwError, type, value, _base; if (id == null) { throw new Error("id is required"); } value = this[id]; if (value != null) { if (value.disposed === true) { value = null; } else { return value; } } throwError = parsed == null; if (parsed == null) { colon = id.indexOf(':'); if (colon > 0) { parsed = { type: id.substring(0, colon), properties: JSON.parse(id.substring(colon + 1)) }; } else { parsed = false; } } if (parsed) { type = parsed.type; properties = parsed.properties; factory = this[type]; if (Object.isFunction(factory)) { properties.parent = this; isClass = factory.properties != null; if (isClass) { value = new factory(properties); } else { value = factory(properties); } } } if (value == null) { value = typeof (_base = this.parent).get === "function" ? _base.get(id, parsed) : void 0; } if (value != null) { this[id] = value; } else if (throwError) { throw new Error("Component not found: " + id); } return value; } }; Component.properties = Component.defineProperties(Component.prototype, properties, Component); getUnderrideName = function(baseDefiningClass, name) { return "" + baseDefiningClass.name + "_subclass_" + name; }; getBaseDefiningClass = function(classDefinition, properties, name) { var baseDefiningClass, baseFunction, baseProperty, callsUnderride, underrideName, underrideProperty; baseProperty = properties[name]; while (true) { baseFunction = baseProperty.value; baseDefiningClass = baseProperty.definingClass; underrideName = getUnderrideName(baseDefiningClass, name); callsUnderride = baseFunction.toString().has(underrideName) || baseFunction.toString().has(/\binner\b/); if (!callsUnderride) { throw new Error("" + classDefinition.name + "." + name + " cannot be defined because " + baseDefiningClass.name + "." + name + " does not call " + underrideName + "."); } underrideProperty = properties[underrideName]; if (underrideProperty != null) { baseProperty = underrideProperty; } else { return baseDefiningClass; } } }; underride = function(classDefinition, properties, rootDefiningClass, name, fn) { var baseDefiningClass; baseDefiningClass = getBaseDefiningClass(classDefinition, properties, name); properties[getUnderrideName(baseDefiningClass, name)] = fn; }; extend = function(baseClass, subClassDefinition) { var baseProperty, name, property, prototype, subClass, subProperties; if (!Object.isString(subClassDefinition != null ? subClassDefinition.id : void 0)) { throw new Error("missing id property"); } subClassDefinition.name = subClassDefinition.id.replace(/[\.\/]/g, '_'); subClass = eval("(function " + subClassDefinition.name + "(properties) {\n this.initialize(properties);\n})"); subProperties = subClassDefinition.properties = Component.normalizeProperties(subClassDefinition.properties, subClass); prototype = subClass.prototype; properties = Object.clone(baseClass.properties); for (name in subProperties) { property = subProperties[name]; baseProperty = properties[name]; if (Object.isFunction(baseProperty != null ? baseProperty.value : void 0)) { if (!Object.isFunction(property.value)) { throw new Error("Functions can only be overridden with other functions: " + property.value); } underride(subClassDefinition, properties, baseProperty.definingClass, name, property.value); } else { properties[name] = property; } } subClassDefinition.properties = properties; Object.merge(subClass, subClassDefinition); Component.defineProperties(prototype, properties, subClass); subClass.extend = function(subClassDefinition) { return extend(subClass, subClassDefinition); }; return subClass; }; Component.extend = function(subClassDefinition) { return extend(Component, subClassDefinition); }; if (typeof describe === 'function') { assert = require('assert'); describe('glass.Component', function() { it("should have an id", function() { return assert(Object.isString(Component.id)); }); it("its toString should return it's id", function() { return assert.equal(Component.toString(), "glass.Component"); }); it("should have a name", function() { return assert.equal(Component.name, "glass_Component"); }); describe('#dispose', function() { it('should mark self disposed', function() { var a; a = new Component({ parent: global }); a.dispose(); return assert(a.disposed); }); it('should dispose of children', function() { var a, b; a = new Component({ parent: global }); b = new Component({ parent: a }); a.dispose(); return assert(b.disposed); }); return it('should remove property from parent', function() { var a; a = new Component({ parent: global }); a.dispose(); return assert(global[a.id] == null); }); }); describe('#defineProperties', function() { return it("should allow primitive values", function() { var object; object = {}; Component.defineProperties(object, { f: function() { return "function"; }, i: 2, b: true, a: [], s: "hello" }); assert(Object.isFunction(object.f)); assert.equal(object.f(), "function"); assert.equal(object.i, 2); assert.equal(object.b, true); assert(Object.equal(object.a, [])); return assert.equal(object.s, "hello"); }); }); describe('#Constructor', function() { it('should set itself as property on parent', function() { var a; a = new Component({ parent: global }); assert(Object.isString(a.id)); assert.equal(global[a.id], a); return a.dispose(); }); it('should require parent', function() { return assert.throws(function() { var a; return a = new Component; }); }); return it('should generate a missing id', function() { var a; a = new Component({ parent: global }); assert(Object.isString(a.id)); return a.dispose(); }); }); describe("#get", function() { it('should throw exception if instance not found', function() { var a; a = new Component({ parent: global }); assert.throws(function() { return a.get("foo"); }); return a.dispose(); }); return it('should create instances with factory', function() { var a, b, c; a = new Component({ parent: global }); b = new Component({ parent: a }); a[Component] = Component; c = b.get('glass.Component:{"x":2,"y":3}'); assert.equal(c.x, 2); assert.equal(c.y, 3); assert.equal(c.parent, a); return a.dispose(); }); }); return describe('extend', function() { it('should inherit base properties', function() { var SubComponent; SubComponent = Component.extend({ id: 'SubComponent' }); return assert(SubComponent.properties.id != null); }); it('should allow underriding constructors and functions', function() { var SubComponent, sub; SubComponent = Component.extend({ id: 'SubComponent', properties: { initialize: function() { this.constructorCalled = true; return this; }, dispose: function() { this.disposeCalled = true; } } }); sub = new SubComponent({ parent: global }); assert(sub.constructorCalled); sub.dispose(); assert(sub.disposed); return assert(sub.disposeCalled); }); it('should allow recursive extension', function() { var AComponent, BComponent; AComponent = Component.extend({ id: 'AComponent', properties: { dispose: function() {} } }); return BComponent = AComponent.extend({ id: 'BComponent', properties: { foo: function() {} } }); }); return it('should not allow final functions to be underridden', function() { var AComponent; AComponent = Component.extend({ id: 'AComponent', properties: { dispose: function() {} } }); return assert.throws(function() { var BComponent; return BComponent = AComponent.extend({ id: 'BComponent', properties: { dispose: function() {} } }); }); }); }); }); } }).call(this); /* //@ sourceMappingURL=Component.map */