Path: blob/master/webroot/rsrc/externals/javelin/ext/view/View.js
12242 views
/**1* A View is a composable wrapper on JX.$N, allowing abstraction of higher-order2* views and a consistent pattern of parameterization. It is intended3* to be used either directly or as a building block for a syntactic sugar layer4* for concise expression of markup patterns.5*6* @provides javelin-view7* @requires javelin-install8* javelin-util9*/10JX.install('View', {11construct : function(attrs, children) {12this._attributes = JX.copy({}, this.getDefaultAttributeValues());13JX.copy(this._attributes, attrs);1415this._rawChildren = {};16this._childKeys = [];1718if (children) {19this.addChildren(JX.$AX(children));20}2122this.setName(this.__class__.__readable__);23},24events: [25'change'26],2728properties: {29'name': null30},3132members : {33_attributes : null,34_rawChildren : null,35_childKeys: null, // keys of rawChildren, kept ordered.36_nextChildKey: 0, // next key to use for a new child3738/*39* Don't override.40* TODO: Strongly typed attribute access (getIntAttr, getStringAttr...)?41*/42getAttr : function(attrName) {43return this._attributes[attrName];44},4546/*47* Don't override.48*/49multisetAttr : function(attrs) {50JX.copy(this._attributes, attrs);51this.invoke('change');52return this;53},5455/*56* Don't override.57*/58setAttr : function(attrName, value) {59this._attributes[attrName] = value;60this.invoke('change');61return this;62},63/*64* Child views can override to specify default values for attributes.65*/66getDefaultAttributeValues : function() {67return {};68},6970/**71* Don't override.72*/73getAllAttributes: function() {74return JX.copy({}, this._attributes);75},7677/**78* Get the children. Don't override.79*/80getChildren : function() {81var result = [];82var should_repack = false;8384var ii;85var key;8687for (ii = 0; ii < this._childKeys.length; ii++) {88key = this._childKeys[ii];89if (this._rawChildren[key] === undefined) {90should_repack = true;91} else {92result.push(this._rawChildren[key]);93}94}9596if (should_repack) {97var new_child_keys = [];98for (ii = 0; ii < this._childKeys.length; ii++) {99key = this._childKeys[ii];100if (this._rawChildren[key] !== undefined) {101new_child_keys.push(key);102}103}104105this._childKeys = new_child_keys;106}107108return result;109},110111/**112* Add children to the view. Returns array of removal handles.113* Don't override.114*/115addChildren : function(children) {116var result = [];117for (var ii = 0; ii < children.length; ii++) {118result.push(this._addChild(children[ii]));119}120this.invoke('change');121return result;122},123124/**125* Add a single child view to the view.126* Returns a removal handle, i.e. an object that has a method remove(),127* that removes the added child from the view.128*129* Don't override.130*/131addChild: function(child) {132var result = this._addChild(child);133this.invoke('change');134return result;135},136137_addChild: function(child) {138var key = this._nextChildKey++;139this._rawChildren[key] = child;140this._childKeys.push(key);141142return {143remove: JX.bind(this, this._removeChild, key)144};145},146147_removeChild: function(child_key) {148delete this._rawChildren[child_key];149this.invoke('change');150},151152/**153* Accept visitors. This allows adding new behaviors to Views without154* having to change View classes themselves.155*156* This implements a post-order traversal over the tree of views. Children157* are processed before parents, and for convenience the results of the158* visitor on the children are passed to it when processing the parent.159*160* The visitor parameter is a callable which receives two parameters.161* The first parameter is the view to visit. The second parameter is an162* array of the results of visiting the view's children.163*164* Don't override.165*/166accept: function(visitor) {167var results = [];168var children = this.getChildren();169for(var ii = 0; ii < children.length; ii++) {170var result;171if (children[ii].accept) {172result = children[ii].accept(visitor);173} else {174result = children[ii];175}176results.push(result);177}178return visitor(this, results);179},180181/**182* Given the already-rendered children, return the rendered result of183* this view.184* By default, just pass the children through.185*/186render: function(rendered_children) {187return rendered_children;188}189}190});191192193