Anatomy of a Control
For the software developer under a deadline, sometimes a thoughtful comment in source code can make all the difference. With that in mind, here's a look at the kind definition for a control called PrevNextBanner:
// enyo.kind is our constructor factory. // // - a constructor is a function-intended-as-an-argument-to-new // (we often abbreviate as 'ctor'). // e.g. foo = new ctor(); // "ctor" is the constructor // - enyo.kind generates constructors. // // The factory builds a constructor with a number of value-adds which // come from built in features, global pluggable features, and prototype- // specific pluggable features. // // The argument to the factory is a single object we call a // 'configuration'. Configurations are also used in 'components' and // 'chrome' blocks, and in calls to opus.create. // // In this way, a data object can interchangeably describe an instance or // a constructor (exception: the 'create' method, which is only supported // for constructor configurations). // enyo.kind({ // - automatically prepares namespace and stores a reference to the // constructor // i.e. enyo.PrevNextBanner will reference the built constructor. name: "enyo.PrevNextBanner", // - prototype-chaining (aka inheritance): the prototype of the // prototype for this constructor is enyo.HFlexBox. // We can say this constructor is a 'kind' of enyo.HFlexBox. kind: enyo.HFlexBox, // - this is a basic property assignment. 'align' property is supported // by HFlexBox align: "center", // - enyo.Object constructor plug-in support for 'published' properties. // Published properties have automatic getter/setter/changed support. // I.e. publishing a property called 'foo' means the constructor will // have getFoo(), setFoo(<value>), and fooChanged(<newValue>, <oldValue>) // methods. Note that Object also exposes generic getProperty(<name>) // and setProperty(<name>, <value>) methods. published: { previousDisabled: false, nextDisabled: false }, // - enyo.Component constructor plug-in support for 'event' properties. // Event properties allow delegation of methods to client objects. // I.e. publishing an event called 'onFoo' establishes a doFoo(...) // method that essentially calls this.owner[this.onFoo](this, ...). events: { onPrevious: "bannerPrevious", onNext: "bannerNext" }, // - components is an array of configurations that describe Components // owned by this object. components: [ {name: "previous", kind: enyo.Button, className: "enyo-banner-prev", onclick: "doPrevious"}, {name: "client", kind: enyo.HFlexBox, flex: 1, align: "center", className: "enyo-banner-content"}, {name: "next", kind: enyo.Button, className: "enyo-banner-next", onclick: "doNext"} ], create: function() // - part of the DomNode interface, add this CSS class to our // rendered DOM this.addClass('enyo-prev-next-banner'); // - this.inherited(arguments[, newArgsArray]) calls the inherited // version of this method (the nearest implementation of this // method in the prototype chain). // 'arguments' required parameter is literally the JavaScript // special value 'arguments'. // 'newArgsArray' can be used to send a new argument list for the // inherited method. // Note that you can call any inherited method manually with // this syntax: // <name of constructor>.prototype.<method name>.apply(<this>, // <arguments array>) // e.g. enyo.HFlexBox.prototype.create.apply(this, // [{align: "center"}]); this.inherited(arguments); // - Constructors that inherit from Component can take a // configuration block as an argument. Component copies those // configuration values into instance properties, but does not // call *changed methods automatically. It's up to each // constructor to call *changed for any properties that might // need side-effects. this.contentChanged(); this.nextDisabledChanged(); this.previousDisabledChanged(); }, // - 'content' property is inherited from Control. Here this property // is simply propagated to this.$.client. // the inherited method is not called, so normal contentChanged // processing is aborted. contentChanged: function() { this.$.client.setContent(this.content); }, // - next/previousDisabled properties are propagated directly to the // underlying buttons. nextDisabledChanged: function() { this.$.next.setDisabled(this.nextDisabled); }, previousDisabledChanged: function() { this.$.previous.setDisabled(this.previousDisabled); } });