foam-framework
Version:
MVC metaprogramming framework
200 lines (192 loc) • 6.03 kB
JavaScript
/**
* @license
* Copyright 2015 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.
*/
CLASS({
package: 'foam.u2',
name: 'ChoiceViewTrait',
properties: [
{
model_: 'BooleanProperty',
name: 'autoSetData',
documentation: 'When true, this.data will be set if choices are set ' +
'and the current data is not one of the choices.',
defaultValue: true
},
{
name: 'prop',
hidden: true
},
{
name: 'label',
documentation: 'The user-visible label for this View. Not to be ' +
'confused with $$DOC{ref:".text"}, the name of the currently ' +
'selected choice.',
postSet: function(old, nu) {
for (var i = 0; i < this.choices.length; i++) {
if (this.choices[i][1] === nu) {
if (this.index !== i) this.index = i;
return;
}
}
},
},
{
name: 'choice',
documentation: 'The current choice (ie. [value, text] pair).',
getter: function() {
var value = this.data;
for (var i = 0; i < this.choices.length; i++) {
var choices = this.choices[i];
if (value === choices[0]) return choice;
}
return undefined;
},
setter: function(nu) {
var oldValue = this.choice;
this.data = nu[0];
this.text = nu[1];
this.propertyChange('choice', oldValue, this.choice);
}
},
{
name: 'choices',
type: 'Array[StringField]',
documentation: 'Array of [value, text] choices. Simple String values ' +
'are expanded to [str, str]. Can also be a map, which results in ' +
'[key, value] pairs listed in enumeration order.',
factory: function() { return []; },
preSet: function(_, a) {
if (typeof a === 'object' && !Array.isArray(a)) {
var out = [];
for (var key in a) {
if (a.hasOwnProperty(key))
out.push([key, a[key]]);
}
return out;
}
a = a.clone();
// Upgrade single values to [value, value].
for (var i = 0; i < a.length; i++) {
if (!Array.isArray(a[i])) {
a[i] = [a[i], a[i]];
}
}
return a;
},
postSet: function(old, nu) {
var value = this.data;
// Update current choice when choices update.
for (var i = 0; i < nu.length; i++) {
var choice = nu[i];
if (value === choice[0]) {
if (this.useSelection)
this.index = i;
else
this.choice = choice;
break;
}
}
if (this.autoSetData && i === nu.length) {
if (this.useSelection) this.index = 0;
else this.data = nu.length ? nu[0][0] : undefined;
}
// TODO(braden): Make sure that updating the labels, with or without
// changing the length of choices, updates the DAO properly.
},
},
{
model_: 'IntProperty',
name: 'index',
documentation: 'The index of the current choice in $$DOC{ref:".choices"}.',
transient: true,
defaultValue: -1,
preSet: function(old, nu) {
if (nu < 0 || this.choices.length === 0) return 0;
if (nu >= this.choices.length) return this.choices.length - 1;
return nu;
},
postSet: function(old, nu) {
// If useSelection is enabled, don't update data or choice.
if (this.useSelection) return;
if (this.choices.length && this.data !== this.choices[nu][0])
this.data = this.choices[nu][0];
},
},
{
model_: 'FunctionProperty',
name: 'objToChoice',
documentation: 'A Function which adapts an object from the DAO to a [key, value, ...] choice.'
},
{
model_: 'BooleanProperty',
name: 'useSelection',
documentation: 'When set, data and choice do not update until an entry is firmly selected',
},
{
model_: 'foam.core.types.DAOProperty',
name: 'dao',
onDAOUpdate: 'onDAOUpdate'
},
{
name: 'data',
postSet: function(old, nu) {
for ( var i = 0 ; i < this.choices.length ; i++ ) {
if ( this.choices[i][0] === nu ) {
if ( this.index !== i ) {
this.text = this.choices[i][1];
this.index = i;
}
return;
}
}
if ( ! nu && this.autoSetData ) {
if (this.useSelection) this.index = 0;
else if ( this.choices.length )this.data = this.choices[0][0];
}
if ( nu && this.choices.length )
console.warn('ChoiceView data set to invalid choice: ', nu);
}
},
{
name: 'text',
documentation: 'The label for the currently selected choice. (ie. choice[1]).',
},
],
listeners: [
{
name: 'onDAOUpdate',
isFramed: true,
code: function() {
this.dao.select(MAP(this.objToChoice))(function(map) {
this.choices = map.arg2;
}.bind(this));
}
},
],
methods: [
function findChoiceIC(name) {
name = name.toLowerCase();
for (var i = 0; i < this.choices.length; i++) {
if (this.choices[i][1].toLowerCase() === name) return this.choices[i];
}
},
function commit() {
if (this.useSelection && this.choices[this.index]) {
this.choice = this.choices[this.index];
}
},
]
});