UNPKG

foam-framework

Version:
971 lines (946 loc) 31.6 kB
/** * @license * Copyright 2012 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ GLOBAL.Property = { __proto__: BootstrapModel, instance_: {}, name: 'Property', plural:'Properties', help: 'Describes a properties of a modelled entity.', ids: [ 'name' ], tableProperties: [ 'name', 'label', 'type', 'required', 'defaultValue' ], documentation: function() { /* <p>The $$DOC{ref:'Property',usePlural:true} of a $$DOC{ref:'Model'} act as data members and connection points. A $$DOC{ref:'Property'} can store a modelled value, and bind to other $$DOC{ref:'Property',usePlural:true} for easy reactive programming.</p> <p>Note that, like $$DOC{ref:'Model'} being a $$DOC{ref:'Model'} itself, the $$DOC{ref:'Model.properties'} feature of all models is itself a $$DOC{ref:'Property'}. <p> */}, properties: [ { name: 'name', type: 'String', required: true, displayWidth: 30, displayHeight: 1, defaultValue: '', mode: 'read-only', // TODO: this should be 'final' when available help: 'The coding identifier for the property.', documentation: function() { /* The identifier used in code to represent this $$DOC{ref:'.'}. $$DOC{ref:'.name'} should generally only contain identifier-safe characters. $$DOC{ref:'.'} names should use camelCase staring with a lower case letter. */} }, { name: 'labels', type: 'Array', subType: 'String', labels: ['debug', 'javascript'], }, { name: 'label', type: 'String', required: false, displayWidth: 70, displayHeight: 1, defaultValueFn: function() { return labelize(this.name); }, help: 'The display label for the property.', documentation: function() { /* A human readable label for the $$DOC{ref:'.'}. May contain spaces or other odd characters. */} }, { name: 'speechLabel', type: 'String', required: false, displayWidth: 70, displayHeight: 1, defaultValueFn: function() { return this.label; }, help: 'The speech label for the property.', documentation: function() { /* A speakable label for the $$DOC{ref:'.'}. Used for accesibility. */} }, { name: 'tableLabel', type: 'String', displayWidth: 70, displayHeight: 1, defaultValueFn: function() { return this.label; }, help: 'The table display label for the entity.', documentation: function() { /* A human readable label for the $$DOC{ref:'Model'} for use in tables. May contain spaces or other odd characters. */} }, { name: 'type', type: 'String', required: true, // todo: curry arguments view: { factory_: 'foam.ui.ChoiceView', choices: [ 'Array', 'Boolean', 'Color', 'Date', 'DateTime', 'Email', 'Enum', 'Float', 'Function', 'Image', 'Int', 'Object', 'Password', 'String', 'String[]', 'URL' ] }, defaultValue: 'String', help: 'The type of the property.', documentation: function() { /* <p>The type of the $$DOC{ref:'.'}, either a primitive type or a $$DOC{ref:'Model'}.</p> <p>Primitives include:</p> <ul> <li>Array</li> <li>Boolean</li> <li>Color</li> <li>Date</li> <li>DateTime</li> <li>Email</li> <li>Enum</li> <li>Float</li> <li>Function</li> <li>Image</li> <li>Int</li> <li>Object</li> <li>Password</li> <li>String</li> <li>String[]</li> <li>URL</li> </ul> */} }, { name: 'swiftDefaultValue', labels: ['swift'], defaultValueFn: function() { if (this.defaultValue == undefined) return 'nil'; switch(typeof this.defaultValue) { case "string": return '"' + this.defaultValue + '"'; default: return this.defaultValue; } } }, { name: 'protobufType', type: 'String', required: false, help: 'The protobuf type that represents the type of this property.', defaultValueFn: function() { return this.type.toLowerCase(); }, documentation: function() {/* When generating protobuf definitions, specifies the type to use for the field this represents. */} }, { name: 'javaType', type: 'String', required: false, defaultValueFn: function() { return this.type; }, help: 'The java type that represents the type of this property.', documentation: function() { /* When running FOAM in a Java environment, specifies the Java type or class to use. */} }, { name: 'javascriptType', type: 'String', required: false, defaultValueFn: function() { return this.type; }, help: 'The javascript type that represents the type of this property.', documentation: function() { /* When running FOAM in a javascript environment, specifies the javascript type to use. */} }, { name: 'swiftType', type: 'String', required: false, labels: ['swift'], defaultValueFn: function() { var type = this.type; if (this.type == 'Boolean') { type = 'Bool'; } else if (this.type == 'int') { type = 'Int'; } return type + (!this.required ? '?' : ''); }, help: 'The Swift type that represents this type of property.', }, { name: 'shortName', type: 'String', required: true, displayWidth: 10, displayHeight: 1, defaultValue: '', help: 'A short alternate name to be used for compact encoding.', documentation: "A short alternate $$DOC{ref:'.name'} to be used for compact encoding." }, { name: 'singular', type: 'String', required: false, displayWidth: 70 }, { name: 'aliases', type: 'Array[String]', labels: ['javascript'], view: 'foam.ui.StringArrayView', factory: function() { return []; }, help: 'Alternate names for this property.', documentation: function() { /* Aliases can be used as synonyms for this $$DOC{ref:'Property'} in code or to look it up by name. */} }, { name: 'mode', type: 'String', defaultValue: 'read-write', view: { factory_: 'foam.ui.ChoiceView', choices: ['read-only', 'read-write', 'final'] }, documentation: function() { /* To restrict modification to a $$DOC{ref:'Property'}, the $$DOC{ref:'.mode'} can be set to read-only to block changes, or to final to block overriding this $$DOC{ref:'Property'} in descendents of the $$DOC{ref:'Model'} that owns this $$DOC{ref:'Property'}. */} }, { name: 'subType', label: 'Sub-Type', type: 'String', displayWidth: 30, // todo: keyView of Models help: 'The type of the property.', documentation: function() { /* In array types, the $$DOC{ref:'.subType'} indicates the type that the array contains. */} }, { name: 'subKey', type: 'EXPR', labels: ['javascript'], displayWidth: 20, defaultValue: 'ID', help: 'The foreign key that this property references.', documentation: function() {/* Used to project whole objects of $$DOC{ref:'.subType'} into the value of this Property. For foreign key properties, this is the foreign property. For eg. an email property, when the subType is a whole Contact object, subKey will be EMAIL. */} }, { name: 'units', type: 'String', required: true, displayWidth: 70, displayHeight: 1, defaultValue: '', help: 'The units of the property.', documentation: function() { /* The units of the $$DOC{ref:'Property'}. */} }, { name: 'required', type: 'Boolean', view: 'foam.ui.BooleanView', defaultValue: true, help: 'Indicates if the property is a required field.', documentation: function() { /* Indicates whether the $$DOC{ref:'Property'} is required for its owner $$DOC{ref:'Model'} to function properly. */} }, { // For U2, replaces hidden name: 'visibility', choices: [ 'rw', 'final', 'ro', 'hidden' ], postSet: function(_, v) { if ( 'hidden' === v ) this.hidden = true; } }, { name: 'hidden', type: 'Boolean', view: 'foam.ui.BooleanView', defaultValue: false, postSet: function(old, hidden) { if ( (! old) && hidden ) this.visibility = 'hidden'; }, help: 'Indicates if the property is hidden.', documentation: function() { /* Indicates whether the $$DOC{ref:'Property'} is for internal use and should be hidden from the user when viewing tables or other views of $$DOC{ref:'Model'} $$DOC{ref:'Property',usePlural:true}. */} }, { name: 'transient', type: 'Boolean', view: 'foam.ui.BooleanView', defaultValue: false, help: 'Indicates if the property is transient.', documentation: function() { /* Indicates whether the $$DOC{ref:'Property'} is transient, and should not be saved permanently or serialized. */} }, { name: 'modelId', type: 'String', view: 'foam.ui.TextFieldView', help: 'Id of the model that this is a property of', transient: true }, { name: 'displayWidth', type: 'int', displayWidth: 8, displayHeight: 1, defaultValue: 30, help: 'The display width of the property.', documentation: function() { /* A width suggestion for views that automatically render the $$DOC{ref:'Property'}. */} }, { name: 'displayHeight', type: 'int', displayWidth: 8, displayHeight: 1, defaultValue: 1, help: 'The display height of the property.', documentation: function() { /* A height suggestion for views that automatically render the $$DOC{ref:'Property'}. */} }, { // model_: 'ViewFactoryProperty', name: 'view', type: 'view', labels: ['javascript'], defaultValue: 'foam.ui.TextFieldView', help: 'View component for the property.', documentation: function() { /* The default $$DOC{ref:'foam.ui.View'} to use when rendering the $$DOC{ref:'Property'}. Specify a string or an object with factory_ and other properties specified. */} }, { // model_: 'ViewFactoryProperty', name: 'toPropertyE', labels: ['javascript'], defaultValue: function toPropertyE(X) { var e = this.displayHeight > 1 ? X.lookup('foam.u2.TextArea').create(null, X) : X.lookup('foam.u2.Input').create(null, X) ; e.attrs({size: this.displayWidth}); return e; } }, { // model_: 'ViewFactoryProperty', name: 'detailView', type: 'view', labels: ['javascript'], defaultValueFn: function() { return this.view; }, help: 'View component for the property when rendering within a DetailView.', documentation: function() { /* The default $$DOC{ref:'foam.ui.View'} to use when rendering the $$DOC{ref:'Property'} as a part of a $$DOC{ref:'foam.ui.DetailView'}. Specify a string or an object with factory_ and other properties specified. */} }, { // model_: 'ViewFactoryProperty', name: 'citationView', type: 'view', labels: ['javascript'], defaultValueFn: function() { return this.view; }, help: 'View component for the property when rendering within a CitationView.', documentation: function() { /* The default $$DOC{ref:'foam.ui.View'} to use when rendering the $$DOC{ref:'Property'} as a part of a $$DOC{ref:'CitationView'}. Specify a string or an object with factory_ and other properties specified. */} }, { name: 'swiftView', type: 'String', labels: ['swift'], defaultValueFn: function() { return this.view.substring(this.view.lastIndexOf('.')+1); }, help: 'The default view name for this property in swift.' }, { // model_: 'FunctionProperty', name: 'detailViewPreRow', labels: ['javascript'], defaultValue: function() { return ""; }, help: 'Inject HTML before row in DetailView.', documentation: function() { /* An optional function to inject HTML before the row in $$DOC{ref:'foam.ui.DetailView'}. */} }, { // model_: 'FunctionProperty', name: 'detailViewPostRow', labels: ['javascript'], defaultValue: function() { return ""; }, help: 'Inject HTML before row in DetailView.', documentation: function() { /* An optional function to inject HTML after the row in $$DOC{ref:'foam.ui.DetailView'}. */} }, { name: 'defaultValue', type: 'String', required: false, displayWidth: 70, displayHeight: 1, defaultValue: '', postSet: function(old, nu) { if ( nu && this.defaultValueFn ) this.defaultValueFn = undefined; }, help: 'The property\'s default value.', documentation: function() { /* An optional function to inject HTML before the row in $$DOC{ref:'foam.ui.DetailView'}. */} }, { name: 'defaultValueFn', label: 'Default Value Function', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', postSet: function(old, nu) { if ( nu && this.defaultValue ) this.defaultValue = undefined; }, help: 'The property\'s default value function.', documentation: function() { /* Optional function that is evaluated when a default value is required. Will unset any $$DOC{ref:'.defaultValue'} that has been set. */} }, { name: 'dynamicValue', label: "Value's Dynamic Function", type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', help: "A dynamic function which computes the property's value.", documentation: function() { /* Allows the value of this $$DOC{ref:'Property'} to be calculated dynamically. Other $$DOC{ref:'Property',usePlural:true} and bindable objects used inside the function will be automatically bound and the function re-evaluated when a dependency changes. */} }, { name: 'factory', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'Factory for creating initial value when new object instantiated.', documentation: function() { /* An optional function that creates the instance used to store the $$DOC{ref:'Property'} value. This is useful when the $$DOC{ref:'Property'} type is a complex $$DOC{ref:'Model'} that requires construction parameters. */} }, { name: 'lazyFactory', type: 'Function', labels: ['javascript'], required: false, view: 'foam.ui.FunctionView', help: 'Factory for creating the initial value. Only called when the property is accessed for the first time.', documentation: function() { /* Like the $$DOC{ref:'.factory'} function, but only evaulated when this $$DOC{ref:'Property'} is accessed for the first time. */} }, { name: 'validate', type: 'Function', labels: ['javascript'], required: false, view: 'foam.ui.FunctionView', help: 'Function for validating property value.', preSet: function(_, f) { var str = f.toString(); var deps = str. match(/^function[ _$\w]*\(([ ,\w]*)/)[1]. split(','). map(function(name) { return name.trim(); }); var f2 = function() { var args = []; for ( var i = 0 ; i < deps.length ; i++ ) args.push(this[deps[i]]); return f.apply(this, args); }; f2.dependencies = deps; f2.toString = function() { return f.toString(); }; return f2; }, documentation: function() { /* */} }, { name: 'swiftAdapt', type: 'String', labels: ['compiletime', 'swift'], defaultValue: 'return newValue', }, { name: 'swiftPreSet', type: 'String', labels: ['compiletime', 'swift'], defaultValue: 'return newValue', }, { name: 'swiftPostSet', type: 'String', labels: ['compiletime', 'swift'], defaultValue: '//swiftPostSet goes here.', }, { name: 'swiftGetter', type: 'String', labels: ['compiletime', 'swift'], defaultValue: 'return <%= this.name %>_', }, { name: 'getter', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'The property\'s default value function.', documentation: function() { /* For advanced use. Supplying a $$DOC{ref:'.getter'} allows you to completely re-implement the $$DOC{ref:'Property'} storage mechanism, to calculcate the value, or cache, or pre-process the value as it is requested. In most cases you can just supply a $$DOC{ref:'.preSet'} or $$DOC{ref:'.postSet'} instead. */} }, { name: 'adapt', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'An adapter function called before preSet.', documentation: function() { /* Allows you to modify the incoming value before it is set. Parameters <code>(old, nu)</code> are supplied with the old and new value. Return the value you want to be set. */} }, { name: 'preSet', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'An adapter function called before normal setter logic.', documentation: function() { /* Allows you to modify the incoming value before it is set. Parameters <code>(old, nu)</code> are supplied with the old and new value. Return the value you want to be set. */} }, { name: 'postSet', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'A function called after normal setter logic, but before property change event fired.', documentation: function() { /* Allows you to react after the value of the $$DOC{ref:'Property'} has been set, but before property change event is fired. Parameters <code>(old, nu)</code> are supplied with the old and new value. */} }, { name: 'setter', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'The property\'s default value function.', documentation: function() { /* For advanced use. Supplying a $$DOC{ref:'.setter'} allows you to completely re-implement the $$DOC{ref:'Property'} storage mechanism, to calculcate the value, or cache, or pre-process the value as it is set. In most cases you can just supply a $$DOC{ref:'.preSet'} or $$DOC{ref:'.postSet'} instead. */} }, { name: 'tableFormatter', label: 'Table Cell Formatter', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'Function to format value for display in TableView.', documentation: "A function to format the value for display in a $$DOC{ref:'foam.ui.TableView'}." }, { name: 'summaryFormatter', label: 'Summary Formatter', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'Function to format value for display in SummaryView.', documentation: "A function to format the value for display in a $$DOC{ref:'SummaryView'}." }, { name: 'tableWidth', type: 'String', required: false, defaultValue: '', help: 'Table View Column Width.', documentation: "A Suggestion for $$DOC{ref:'foam.ui.TableView'} column width." }, { name: 'help', label: 'Help Text', type: 'String', required: false, displayWidth: 70, displayHeight: 6, view: 'foam.ui.TextAreaView', defaultValue: '', help: 'Help text associated with the property.', documentation: function() { /* This $$DOC{ref:'.help'} text informs end users how to use the $$DOC{ref:'Property'}, through field labels or tooltips. */} }, DocumentationBootstrap, { name: 'prototag', label: 'Protobuf tag', type: 'Int', defaultValue: 0, required: false, help: 'The protobuf tag number for this field.', documentation: 'The protobuf tag number for this field.' }, { name: 'actionFactory', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', help: 'Factory to create the action objects for taking this property from value A to value B', documentation: "Factory to create the $$DOC{ref:'Action'} objects for taking this $$DOC{ref:'Property'} from value A to value B" }, { name: 'compareProperty', type: 'Function', labels: ['javascript'], view: 'foam.ui.FunctionView', displayWidth: 70, displayHeight: 5, defaultValue: function(o1, o2) { if ( o1 === o2 ) return 0; if ( ! o1 && ! o2 ) return 0; if ( ! o1 ) return -1; if ( ! o2 ) return 1; if ( o1.localeCompare ) return o1.localeCompare(o2); if ( o1.compareTo ) return o1.compareTo(o2); return o1.$UID.compareTo(o2.$UID); }, help: 'Comparator function.', documentation: "A comparator function two compare two instances of this $$DOC{ref:'Property'}." }, { name: 'fromString', labels: ['javascript'], defaultValue: function(s, p) { this[p.name] = s; }, help: 'Function to extract value from a String.' }, { name: 'fromElement', labels: ['javascript'], defaultValue: function propertyFromElement(e, p) { if ( ! p.type || ! this.X.lookup || p.type === 'String' ) { p.fromString.call(this, e.innerHTML, p); return; } var model = this.X.lookup(p.type); if ( ! model ) { p.fromString.call(this, e.innerHTML, p); return; } var o = model.create(); if ( ! o.fromElement ){ p.fromString.call(this, e.innerHTML, p); return; } this[p.name] = o.fromElement(e); }, help: 'Function to extract from a DOM Element.', documentation: "Function to extract a value from a DOM Element." }, { name: 'propertyToJSON', labels: ['javascript'], defaultValue: function(visitor, output, o) { if ( ! this.transient ) output[this.name] = visitor.visit(o[this.name]); }, help: 'Function to extract from a DOM Element.', documentation: "Function to extract a value from a DOM Element." }, { name: 'autocompleter', subType: 'Autocompleter', labels: ['javascript'], help: 'Name or model for the autocompleter for this property.', documentation: function() { /* Name or $$DOC{ref:'Model'} for the $$DOC{ref:'Autocompleter'} for this $$DOC{ref:'Property'}. */} }, { name: 'install', type: 'Function', labels: ['javascript'], required: false, displayWidth: 70, displayHeight: 3, rows:3, view: 'foam.ui.FunctionView', defaultValue: '', help: "A function which installs additional features into the Model's prototype.", documentation: function() { /* A function which installs additional features into our $$DOC{ref:'Model'} prototype. This allows extra language dependent features or accessors to be added to instances for use in code. */} }, { name: 'exclusive', type: 'Boolean', view: 'foam.ui.BooleanView', defaultValue: true, help: 'Indicates if the property can only have a single value.', documentation: function() { /* Indicates if the $$DOC{ref:'Property'} can only have a single value. */} }, { name: 'memorable', type: 'Boolean', help: 'True if this value should be included in a memento for this object.', defaultValue: false }, { name: 'attribute', type: 'Boolean', help: 'True if this property is settable as an element attribute.', defaultValue: false } ], methods: [ function partialEval() { return this; }, { name: 'f', code: function(obj) { return obj[this.name] }, swiftSource: function() {/* func f(obj: AnyObject?) -> AnyObject? { if obj == nil { return nil } if let fobj = obj as? FObject { return fobj.get(self.name) } return nil }*/}, }, { name: 'compare', code: function(o1, o2) { return this.compareProperty(this.f(o1), this.f(o2)); }, swiftSource: function() {/* func compare(var o1: AnyObject?, var o2: AnyObject?) -> Int { o1 = self.f(o1) o2 = self.f(o2) if o1 === o2 { return 0 } if o1 == nil && o2 == nil { return 0 } if o1 == nil { return -1 } if o2 == nil { return 1 } if o1!.isEqual(o2) { return 0 } return o1?.hashValue > o2?.hashValue ? 1 : -1 } */} }, function readResolve() { return this.modelId ? this.X.lookup(this.modelId)[constantize(this.name)] : this; }, function toSQL() { return this.name; }, function toMQL() { return this.name; }, function toBQL() { return this.name; }, function cloneProperty(/* this=prop, */ value) { return ( value && value.clone ) ? value.clone() : value; }, function deepCloneProperty(/* this=prop, */ value) { return ( value && value.deepClone ) ? value.deepClone() : value; }, function exprClone() { return this; }, function dot(nextProp) { var PropertySequence = this.X.lookup('foam.mlang.PropertySequence'); if ( ! PropertySequence ) { console.warn('Missing foam.mlang.PropertySequence for Property.dot()'); return this; } if ( PropertySequence.isInstance(this) ) { if ( this.next_ ) this.next_ = this.next_.dot(nextProp); else this.next_ = nextProp; return this; } else { return PropertySequence.xbind({ next_: nextProp }).create(this, this.Y); } }, function initPropertyAgents(proto, fastInit) { var prop = this; var name = prop.name; var name$_ = prop.name$_; if ( ! fastInit ) proto.addInitAgent( (this.postSet || this.setter) ? 9 : 0, name + ': ' + (this.postSet || this.setter ? 'copy arg (postSet)' : 'copy arg'), function(o, X, m) { if ( ! m ) return; if ( m.hasOwnProperty(name) ) o[name] = m[name]; if ( m.hasOwnProperty(name$_) ) o[name$_] = m[name$_]; } ); if ( this.dynamicValue ) { var dynamicValue = prop.dynamicValue; if ( Array.isArray(dynamicValue) ) { proto.addInitAgent(10, name + ': dynamicValue', function(o, X) { Events.dynamic( dynamicValue[0].bind(o), function() { o[name] = dynamicValue[1].call(o); }, X || this.X); }); } else { proto.addInitAgent(10, name + ': dynamicValue', function(o, X) { Events.dynamic( dynamicValue.bind(o), function(value) { o[name] = value; }, X || this.X); }); } } if ( this.factory ) { proto.addInitAgent(11, name + ': factory', function(o, X) { if ( ! o.hasOwnProperty(name) ) o[name]; }); } }, function toE(opt_X) { var X = opt_X || this.X; return X.lookup('foam.u2.PropertyView').create({prop: this, view: this.toPropertyE(X)}, X); } ], //templates: [ // { // model_: 'Template', // name: 'closureSource', // description: 'Closure Externs JavaScript Source', // template: // '/**\n' + // ' * @type {<%= this.javascriptType %>}\n' + // ' */\n' + // '<%= arguments[1] %>.prototype.<%= this.name %> = undefined;' // } //], toString: function() { return "Property"; } }; Model.methods = {}; "createMethod_ getProperty getAction hashCode buildPrototype addTraitToModel_ buildProtoImports_ buildProtoProperties_ buildProtoMethods_ getPrototype isSubModel isInstance getAllRequires arequire getMyFeature getRawFeature getAllMyRawFeatures getFeature getAllRawFeatures atest getRuntimeProperties getRuntimeActions create".split(' ').forEach(function(k) { Model.methods[k] = BootstrapModel[k]; }); // This is the coolest line of code that I've ever written // or ever will write. Oct. 4, 2011 -- KGR Model = Model.create(Model); Model.model_ = Model; Model.create = BootstrapModel.create; Property = Model.create(Property); // Property properties are still Bootstrap Models, so upgrade them. var ps = Property.getRuntimeProperties(); for ( var i = 0 ; i < ps.length ; i++ ) { Property[constantize(ps[i].name)] = ps[i] = Property.create(ps[i]); } USED_MODELS.Property = true; USED_MODELS.Model = true;