spincycle
Version:
A reactive message router and object manager that lets clients subscribe to object property changes on the server
434 lines (385 loc) • 19.2 kB
HTML
<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/paper-listbox/paper-listbox.html">
<link rel="import" href="../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../bower_components/iron-icons/maps-icons.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/paper-input/paper-input.html">
<link rel="import" href="../../bower_components/paper-input/paper-textarea.html">
<link rel="import" href="../../bower_components/paper-dialog/paper-dialog.html">
<link rel="import" href="../../bower_components/ace-widget/ace-widget.html">
<link rel="import" href="../../bower_components/carbon-i18n-behavior/carbon-i18n-behavior.html">
<script src="../i18n/spin-model.en.i18.js"></script>
<script src="../i18n/spin-model.se.i18.js"></script>
<link rel="import" href="spin-directreference.html">
<link rel="import" href="my-objarray.html">
<dom-module id="spin-model">
<template>
<style>
paper-button.fancy {
background: #0062A2;
color: white;
width: 250px;
margin-bottom: 10px;
text-transform:none;
box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
}
</style>
<template is="dom-if" if="{{doshow}}">
<h4>{{model.name}}</h4>
<paper-button raised class="fancy" on-tap="saveModel">Save</paper-button>
<paper-listbox>
<!-- <paper-button on-tap="saveModel">Save</paper-button> -->
<my-objarray object="{{model}}" array="{{array}}"></my-objarray>
<template id="modeltemplate" is="dom-repeat" items="{{array}}">
<div style="display:flex; flex-direction:row">
<paper-item >
<!-- {{item.key}}__ -->
<template is="dom-if" if="{{isType(item,'array')}}">
<spin-list propname="{{item.key}}" delete="true" incallbacks="[[outCallbacks]]" client="{{client}}" user="{{user}}" model="{{getTypeFor(item)}}" spinids="{{item.value}}" itemselected="{{selectedlistitem}}" show="true"></spin-list>
<paper-button raised on-tap="addModel">[[i18n.add]] {{getTypeFor(item)}}</paper-button>
<paper-dialog style="padding:20px;overflow:auto" id="addmodeldialog_{{getModelId()}}_{{getTypeFor(item)}}">
<h2>[[i18n.add]] {{item.type}}</h2>
<spin-allmodels client="{{client}}" user="{{user}}" incallbacks="{{dialogCallbacks}}" listitemselected="{{dialoglistitemselected}}" model="{{getTypeFor(item)}}"></spin-allmodels>
<div class="buttons">
<paper-button dialog-dismiss>[[i18n.cancel]]</paper-button>
<paper-button dialog-confirm>[[i18n.accept]]</paper-button>
</div>
</paper-dialog>
</template>
<template is="dom-if" if="{{isType(item,'ref')}}">
<spin-directreference client="{{client}}" user="{{user}}" incallbacks="{{dialogCallbacks}}" propname="{{item.key}}" modelid="{{item.value}}" modeltype="{{getTypeFor(item)}}" ></spin-directreference>
</template>
<template is="dom-if" if="{{isType(item,'scalar')}}">
<paper-textarea id="{{item.key}}" label="[[getLabelFor(item.key)]]" disabled="{{item.disabled}}" type="text" value="{{item.value::input}}" on-keyup="onInputChange" autoSave="true" stopKeyboardEventPropagation="true" style="width:600px">
</paper-textarea>
</template>
<template is="dom-if" if="{{isType(item,'timestamp')}}">
<paper-textarea label="[[getLabelFor(item.key)]]" disabled="{{item.disabled}}" type="text" value="{{getDateFor(item.value)}}" on-keyup="onInputChange" autoSave="true" stopKeyboardEventPropagation="true" style="width:600px">
</paper-textarea>
</template>
<template is="dom-if" if="{{isType(item,'code')}}">
<div style="display:flex;flex-direction: row; justify-content: space-between;width:600px">
<strong style="padding-right:20px;">[[getLabelFor(item.key)]]</strong>
<ace-widget on-editor-content="onEditorContent" style="width:500px;height:300px;">{{item.value}}</ace-widget>
</div>
</template>
</paper-item>
</div>
</template>
</paper-listbox>
</template>
</template>
<script>
Polymer({
is: 'spin-model',
properties:
{
client:{type:'Object'},
model: {type: 'Object', notify:true, value: function() {return new Object()}, observer: 'onModelChanged' },
modelproperties: {type: 'Array', observer: 'onModelProperties'},
incallbacks: {type: 'Object'},
selectedlistitem:{type:'Object', notify:true, observer:'onListItemSelect'},
dialoglistitemselected:{type:'Object', observer:'onDialogSelect'},
readonlyproperties: {type: 'Array', value: ['id']}
},
locale:
{
type: String,
value: 'en'
},
behaviors: [
Polymer.CarbonI18nBehavior
],
showing: function()
{
console.log('this.doshow = '+this.doshow)
return this.doshow
},
onEditorContent:function(i)
{
console.log('onEditorContent called for '+i)
console.dir(i)
var key = i.model.item.key
var value = i.detail.value
console.log('setting mode property '+key+' to '+value)
this.set('model.'+key, value)
},
getLabelFor:function(key)
{
return this.i18n[key] || key
},
getDateFor:function(v)
{
return new Date(v).toString()
},
beforeRegister: function()
{
this.observers =
[
'_onModel(model.*)',
'_onArray(array.*)'
]
},
_onModel: function(change)
{
//console.log("test._onItems", change.path);
//console.dir(change)
},
_onArray: function(change)
{
//console.log("test._onArray", change.path);
//console.dir(change)
},
onModelProperties:function(props)
{
//console.log('spin-model ------ onModelProperties')
//console.dir(props)
},
onListItemSelect: function(item)
{
console.log('spin-model onListitemSelected')
//console.dir(item)
//this.onDialogSelect(item)
},
onInputChange:function(e)
{
console.log('onInputChange called')
console.dir(e)
var key = e.model.item.key
var value = e.path[0].value
console.log('key = '+key+', value = '+value)
this.set('model.'+key, value)
},
getTypeFor:function(item)
{
//console.log('getTypeFor '+item.key+' called')
var rv = ''
this.modelproperties.forEach(function(prop)
{
if(prop.name == item.key)
{
rv = prop.type
}
})
//console.log('getTypeFor '+item.key+' return '+rv+' modelprops =')
//console.dir(this.modelproperties)
return rv
},
getModelId:function()
{
var rv = ''
for(var k in this.model)
{
if(k == 'id')
{
rv = this.model[k]
}
}
return rv
},
isType: function(item, what)
{
//console.log('isType called for '+item+' and '+what+' modelproperties = '+this.modelproperties)
//console.dir(item)
var rv = false
if(this.modelproperties)
{
this.modelproperties.forEach( function ( prop )
{
if (prop.name == item.key)
{
//console.log('found '+prop.name)
//console.dir(prop)
if(what == 'timestamp' && prop.name.indexOf('At') > -1)
{
rv = true
}
if(what=='code' && prop.code == true && !prop.array && !prop.type)
{
rv = true
}
if (what == 'scalar' && !prop.array && !prop.type && prop.name.indexOf('At') == -1 && !prop.code)
{
rv = true
}
if (what == 'array' && prop.array == true && !prop.code)
{
rv = true
}
if (what == 'ref' && prop.type && !(prop.array == true) && !prop.code)
{
rv = true
}
}
} )
//console.log('isType called for '+item.key+' and '+what+' returning '+rv)
}
return rv
},
textAreaAutoSave:function(e)
{
console.log('textAreaAutoSave called')
console.dir(e)
},
ready: function()
{
this.doshow = false
this.subscriptions = []
this.dialogCallbacks =
{
onSelect: this.onDialogSelect.bind(this),
onSelectReference: this.onSelectReference.bind(this)
}
this.outCallbacks =
{
onDelete: this.onDeleteListElement.bind(this)
}
},
addModel: function(e)
{
var item = e.model.item
this.modeldialogitem = item
console.log('spin-model addModel called. opening dialog for item')
console.dir(item)
var id = "addmodeldialog_"+this.model.id+"_"+this.getTypeFor(item)
console.log('dialog id -> '+id)
var dialog = this.$$('#'+id)
dialog.open()
},
onDeleteListElement: function(item, propname)
{
console.log('spin-model got delete list item callback for property '+propname)
console.dir(item)
if(confirm('Really remove list item '+item.name+' from '+propname+' list?'))
{
var list = this.model[propname]
console.log( 'current list is ' )
console.dir( list )
var idx = -1
list.forEach( function ( id, i )
{
if (id == item.id)
{
idx = i
}
} )
if (idx > -1)
{
list.splice( idx, 1 )
this.changeValueInArrayFor(propname, [])
this.changeValueInArrayFor(propname, list)
console.log( 'list after is' )
console.dir( this.model[propname] )
this.onItemChange( {model: {item: this.model}} )
}
}
this.onModelChanged(this.model)
},
onSelectReference: function(propname, item)
{
console.log('=======*** spin-model onSelectReference called')
console.dir(item)
this.model[propname] = item.id
this.onItemChange({model:{item:this.model}})
},
onDialogSelect: function(item)
{
console.log('======= spin-model onDialogSelect called')
console.dir(item)
var prop = this.modeldialogitem
console.log('saved prop is')
console.dir(prop)
//this.model[prop.name].push(item)
console.log('======= pushing '+item.type+' '+item.id+' onto array property '+prop.key)
var i = this.getIndexInArrayFor(prop.key)
console.log('index for '+prop.key+' is '+i)
var arr = this.array[i].value
console.log('existing array for '+prop.key+' is '+arr)
arr.push(item.id)
this.changeValueInArrayFor(prop.key, [])
this.changeValueInArrayFor(prop.key, arr)
//this.notifyPath('array.'+i+'.value')
var type = this.getTypeFor(prop)
console.log('======= spin-model added new object to array property '+type)
console.dir(this.model[prop.key])
var id = "addmodeldialog_"+this.model.id+"_"+type
var dialog = this.$$('#'+id)
dialog.close()
},
changeValueInArrayFor:function(propname, value)
{
var idx = this.getIndexInArrayFor(propname)
if(idx > -1)
{
this.set('array.'+idx+'.value', value)
}
},
getIndexInArrayFor:function(propname)
{
var idx = -1
this.array.forEach(function(el, i)
{
if(el.key == propname)
{
idx = i
}
})
return idx
},
saveModel: function()
{
this.onItemChange({model:{item: {}}})
},
onItemChange: function(e)
{
console.log('-------------------- spin-model onItemChange called.')
console.dir(this.model)
this.client.emitMessage({target: '_update'+this.model.type, obj: this.model, type: this.model.type}).then(function(ures)
{
console.log('spin-model update result: '+ures)
}.bind(this))
},
onModelChanged: function(newmodel)
{
//console.log('spin-model onModelChanged called')
//console.dir(newmodel)
//console.log('---------------------------spin-model: i18n is')
//console.dir(this.i18n)
if(newmodel && newmodel.id)
{
this.doshow = true
}
if(newmodel && !this.modelproperties && this.client)
{
this.client.emitMessage({target: 'getModelFor', modelname: newmodel.type}).then(function(mprops)
{
console.log('======================= spin-mode.onModelChanged getModelFor returns ')
console.dir(mprops)
this.set('modelproperties', mprops)
this.set('model', this.model)
this.notifyPath('model', this.model)
}.bind(this))
}
},
onSelect: function(e)
{
console.log('onSelect called at spin-model')
var item = e.model.p
if(this.incallbacks && this.incallbacks.onSelect)
{
this.incallbacks.onSelect(item)
}
this.set('selectedlistitem', item)
},
onDelete:function(e)
{
console.log('onDelete called at spin-model')
var item = e.model.p
if(this.incallbacks && this.incallbacks.onDelete)
{
this.incallbacks.onDelete(item)
}
},
});
</script>
</dom-module>