foam-framework
Version:
MVC metaprogramming framework
205 lines (186 loc) • 5.03 kB
JavaScript
/**
* @license
* Copyright 2014 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.ui',
name: 'MultiLineStringArrayView',
extends: 'foam.ui.View',
properties: [
{
model_: 'StringProperty',
name: 'name'
},
{
model_: 'StringProperty',
name: 'type',
defaultValue: 'text'
},
{
model_: 'IntProperty',
name: 'displayWidth',
defaultValue: 30
},
{
model_: 'BooleanProperty',
name: 'onKeyMode',
defaultValue: true
},
{
model_: 'BooleanProperty',
name: 'autocomplete',
defaultValue: true
},
{
name: 'data'
},
'autocompleter',
{
model_: 'ArrayProperty',
subType: 'foam.ui.MultiLineStringArrayView.RowView',
name: 'inputs'
}
],
models: [
{
model_: 'Model',
name: 'RowView',
extends: 'foam.ui.View',
properties: [
'field',
{
name: 'tagName',
defaultValue: 'div'
}
],
methods: {
toInnerHTML: function() {
this.children = [this.field];
return this.field.toHTML() + '<input type="button" id="' +
this.on('click', (function(){ this.publish('remove'); }).bind(this)) +
'" class="multiLineStringRemove" value="X">';
}
}
}
],
methods: {
toHTML: function() {
var toolbar = ToolbarView.create({
data: this
});
toolbar.addActions([this.model_.ADD]);
this.children = [toolbar];
return '<div id="' + this.id + '"><div></div>' +
toolbar.toHTML() +
'</div>';
},
initHTML: function() {
this.SUPER();
this.data$.addListener(this.update);
this.update();
},
row: function() {
// TODO: Find a better way to copy relevant values as this is unsustainable.
var view = this.model_.RowView.create({
field: this.X.TextFieldView.create({
name: this.name,
type: this.type,
displayWidth: this.displayWidth,
onKeyMode: this.onKeyMode,
autocomplete: this.autocomplete,
autocompleter: this.autocompleter
}, this.Y)
});
return view;
},
setValue: function(value) {
this.value = value;
}
},
listeners: [
{
name: 'update',
code: function() {
if ( ! this.$ ) return;
var inputs = this.inputs;
var inputElement = this.$.firstElementChild;
var newViews = [];
var data = this.data;
// Add/remove rows as necessary.
if ( inputs.length > data.length ) {
for ( var i = data.length; i < inputs.length; i++ ) {
inputs[i].$.remove();
this.removeChild(inputs[i]);
}
inputs.length = data.length;
} else {
var extra = "";
for ( i = inputs.length; i < data.length; i++ ) {
var view = this.row();
// TODO: This seems ridiculous.
this.addChild(view);
newViews.push(view);
inputs.push(view);
view.subscribe('remove', this.onRemove);
view.field.data$.addListener(this.onInput);
extra += view.toHTML();
}
if ( extra ) inputElement.insertAdjacentHTML('beforeend', extra);
}
// Only update the value for a row if it does not match.
for ( i = 0; i < data.length; i++ ) {
if ( inputs[i].field.data !== data[i] )
inputs[i].field.data = data[i];
}
this.inputs = inputs;
for ( i = 0; i < newViews.length; i++ )
newViews[i].initHTML();
}
},
{
name: 'onRemove',
code: function(src) {
var inputs = this.inputs;
for ( var i = 0; i < inputs.length; i++ ) {
if ( inputs[i] === src ) {
this.data = this.data.slice(0, i).concat(this.data.slice(i+1));
break;
}
}
}
},
{
name: 'onInput',
code: function(e) {
if ( ! this.$ ) return;
var inputs = this.inputs;
var newdata = [];
for ( var i = 0; i < inputs.length; i++ ) {
newdata.push(inputs[i].field.data);
}
this.data = newdata;
}
}
],
actions: [
{
name: 'add',
label: 'Add',
code: function() {
this.data = this.data.pushF('');
}
}
]
});