diff --git a/mar/work/command.hoon b/mar/work/command.hoon index 89241ad9cd..5e211171d5 100644 --- a/mar/work/command.hoon +++ b/mar/work/command.hoon @@ -49,14 +49,14 @@ == ++ id (ci (slat %uv) so) ++ ship (su fed:ag) - ++ coma (of new/task old/(ot id/id version/ni dif/uppd ~) sort/(ar id) ~) + ++ coma (of new/task old/(ot id/id dif/uppd ~) sort/(ar id) ~) ++ task %- ot :~ audience/audi - id/id date-created/di - version/ni date-modified/di + id/id 'date_created'^di + version/ni 'date_modified'^di owner/ship status/(ci (soft status) so) - tags/(as so) date-due/(mu di) + tags/(as so) 'date_due'^(mu di) done/(mu di) title/so description/so discussion/(ar (ot date/di ship/ship body/so ~)) == diff --git a/mar/work/report.hoon b/mar/work/report.hoon index c1940b89bb..e16191af4b 100644 --- a/mar/work/report.hoon +++ b/mar/work/report.hoon @@ -24,12 +24,12 @@ claiming/[%b claiming] =< audience/[%a (turn (~(tap in audience)) .)] |=(a=station:talk [%s (crip "{}/{(trip q.a)}")]) - date-created/(jode date-created) - date-modified/(jode date-modified) + 'date_created'^(jode date-created) + 'date_modified'^(jode date-modified) description/[%s description] =< discussion/[%a (turn discussion .)] |=(comment (jobe date/(jode date) ship/(jope ship) body/[%s body] ~)) - date-due/?~(date-due ~ (jode u.date-due)) + 'date_due'^?~(date-due ~ (jode u.date-due)) done/?~(done ~ (jode u.done)) == == diff --git a/pub/work/src/js/actions/WorkActions.coffee b/pub/work/src/js/actions/WorkActions.coffee index 50dabc90f2..7343b7b972 100644 --- a/pub/work/src/js/actions/WorkActions.coffee +++ b/pub/work/src/js/actions/WorkActions.coffee @@ -2,21 +2,22 @@ Dispatcher = require '../dispatcher/Dispatcher.coffee' Persistence = require '../persistence/Persistence.coffee' module.exports = - newItem: (index,list) -> + newItem: (index,_item={}) -> item = - id:window.util.uuid32() - version:0 - "date-created":Date.now() - "date-modified":Date.now() - "date-due":null - done:null - owner:window.urb.ship - status:'announced' - tags:[] - title:'' - description:'' - discussion:[] - audience:[window.util.talk.mainStationPath window.urb.ship] + id: window.util.uuid32() + version: 0 + owner: window.urb.ship + date_created: Date.now() + date_modified: Date.now() + date_due: _item.date_due ? null + done: _item.done ? null + status: _item.status ? 'announced' + tags: _item.tags ? [] + title: _item.title ? '' + description: _item.description ? '' + discussion: _item.discussion ? [] + audience: _item.audience ? + [window.util.talk.mainStationPath window.urb.ship] Persistence.put "new":item Dispatcher.handleViewAction {type:'newItem', index, item} diff --git a/pub/work/src/js/components/FilterComponent.coffee b/pub/work/src/js/components/FilterComponent.coffee index 485b932797..7d80dd2950 100644 --- a/pub/work/src/js/components/FilterComponent.coffee +++ b/pub/work/src/js/components/FilterComponent.coffee @@ -1,6 +1,6 @@ recl = React.createClass rece = React.createElement -[div,h1,label] = [React.DOM.div,React.DOM.h1,React.DOM.label] +{div,h1,label} = React.DOM module.exports = recl _onKeyDown: (e) -> diff --git a/pub/work/src/js/components/ItemComponent.coffee b/pub/work/src/js/components/ItemComponent.coffee index d40402a9c2..e160425eac 100644 --- a/pub/work/src/js/components/ItemComponent.coffee +++ b/pub/work/src/js/components/ItemComponent.coffee @@ -1,19 +1,19 @@ recl = React.createClass -[div,textarea] = [React.DOM.div,React.DOM.textarea] +{div,textarea} = React.DOM WorkActions = require '../actions/WorkActions.coffee' module.exports = recl - _dragStart: (e) -> + onDragStart: (e) -> $t = $(e.target) @dragged = $t.closest('.item') e.dataTransfer.effectAllowed = 'move' e.dataTransfer.setData 'text/html',e.currentTarget @props._dragStart e,@ - _dragEnd: (e) -> @props._dragEnd e,@ + onDragEnd: (e) -> @props._dragEnd e,@ - _keyDown: (e) -> + onKeyDown: (e) -> @props._keyDown e,@ kc = e.keyCode @@ -35,7 +35,7 @@ module.exports = recl if $el[0].tagName is 'TEXTAREA' return $el.val() else - if key is 'date-due' + if key is 'date_due' d = $el.text().slice(1).replace(/\./g, "-") return NaN if d.length < 8 return new Date(d).valueOf() @@ -50,13 +50,13 @@ module.exports = recl compareVal: (l,n,key) -> if key is 'tags' or key is 'audience' return (_.xor(l,n).length > 0) - if key is 'date-due' + if key is 'date_due' return l isnt new Date(n) l isnt n validateField: ($t,id,key,val) -> valid = 1 - if key is 'date-due' + if key is 'date_due' valid = 0 if isNaN(val) if key is 'audience' i = _.filter val,(a) -> @@ -71,7 +71,7 @@ module.exports = recl valid = 0 if i.length isnt val.length valid - _keyUp: (e) -> + onKeyUp: (e) -> $t = $(e.target).closest '.field' id = $t.closest('.item').attr 'data-id' key = $t.attr 'data-key' @@ -88,7 +88,7 @@ module.exports = recl WorkActions.setItem id,ver,key,val ,1000 - _focus: (e) -> @props._focus e,@ + onFocus: (e) -> @props._focus e,@ _markDone: (e) -> id = $(e.target).closest('.item').attr 'data-id' @@ -118,6 +118,15 @@ module.exports = recl getInitialState: -> {expand:false} + renderField: (key,props,format=_.identity)-> + _props = _.extend {}, props, {contentEditable:true,className:'input ib'} + className = "#{props.className ? key} field ib" + (div {className,'data-key':key}, (div _props, format(@props.item[key]))) + + renderTopField: (key,props,format)-> + _props = _.extend {className:"#{props.className ? key} top"}, props + @renderField key,_props,format + render: -> itemClass = 'item' if @state.expand then itemClass += ' expand' @@ -132,79 +141,29 @@ module.exports = recl owner.unshift (div {className:k},@formatOwner(@props.item.owner)) (div { - className:itemClass - draggable:true - 'data-id':@props.item.id - 'data-index':@props.index - onDragStart:@_dragStart - onDragEnd:@_dragEnd + className:itemClass + draggable:true + 'data-id':@props.item.id + 'data-index':@props.index + @onDragStart,@onDragEnd }, [ (div { className:'owner ib' 'data-key':'owner' },owner) - (div { - className:'audience field ib' - 'data-key':'audience' - },[ - (div { - contentEditable:true - className:'input ib' - },@formatAudience(@props.item.audience)) - ]) - (div {className:'sort ib top'},@props.item.sort) - (div { - className:'done ib' - onClick:@_markDone - },'') - (div { - className:'title ib top field' - 'data-key':'title' - },[ - (div { - contentEditable:true - onFocus:@_focus - onKeyDown:@_keyDown - onKeyUp:@_keyUp - className:'input ib' - },@props.item.title) - ]) - (div { - className:'date ib top field' - 'data-key':'date-due' - }, [ - (div { - contentEditable:true - className:'input ib' - onKeyUp:@_keyUp - },@formatDate(@props.item['date-due'])) - ]) - (div { - className:'tags ib top field' - 'data-key':'tags' - },[ - (div { - contentEditable:true - className:'input ib' - onKeyUp:@_keyUp - },@props.item.tags.join(" ")) - ]) + (@renderField 'audience', {}, @formatAudience) # no onKeyUp? + (div {className:'sort ib top'}, @props.item.sort) + (div {className:'done ib', onClick:@_markDone}, '') + (@renderTopField 'title', {@onFocus,@onKeyDown,@onKeyUp}) + (@renderTopField 'date_due', {@onKeyUp,className:'date'}, @formatDate) + (@renderTopField 'tags', {@onKeyUp}, (tags)-> tags.join(" ")) (div { className:'expand ib', - onClick: (e) => - @setState {expand:!@state.expand} - },[ - (div {className:'caret left'},"") - ]) - (div { - className:'description field' - 'data-key':'description' - },[ - (textarea { - className:'input ib' - onKeyUp:@_keyUp - },@props.item.description) - ]) + onClick: (e) => @setState {expand:!@state.expand} + }, (div {className:'caret left'},"") + ) + (@renderField 'description',{@onKeyUp}) + (div {className:"hr"},"") (div {className:"discussion"},[ (div {className:"comments"}, @props.item.discussion.map (slug) => @@ -225,4 +184,4 @@ module.exports = recl (div {className:'submit',onClick:@_submitComment},'Post') ]) ]) - ]) \ No newline at end of file + ]) diff --git a/pub/work/src/js/components/ListComponent.coffee b/pub/work/src/js/components/ListComponent.coffee index d65698ca43..353fe83f8f 100644 --- a/pub/work/src/js/components/ListComponent.coffee +++ b/pub/work/src/js/components/ListComponent.coffee @@ -1,6 +1,6 @@ recl = React.createClass rece = React.createElement -[div,h1,input,textarea] = [React.DOM.div,React.DOM.h1,React.DOM.input,React.DOM.textarea] +{div,h1,input,textarea} = React.DOM WorkStore = require '../stores/WorkStore.coffee' WorkActions = require '../actions/WorkActions.coffee' diff --git a/pub/work/src/js/components/ListeningComponent.coffee b/pub/work/src/js/components/ListeningComponent.coffee index ce9f6b2c21..edada9a164 100644 --- a/pub/work/src/js/components/ListeningComponent.coffee +++ b/pub/work/src/js/components/ListeningComponent.coffee @@ -1,7 +1,7 @@ recl = React.createClass rece = React.createElement -[div,h1,input,textarea] = [React.DOM.div,React.DOM.h1,React.DOM.input,React.DOM.textarea] +{div,h1,input,textarea} = React.DOM module.exports = recl render: -> - (div {className:'listening'}, "") \ No newline at end of file + (div {className:'listening'}, "") diff --git a/pub/work/src/js/components/SortComponent.coffee b/pub/work/src/js/components/SortComponent.coffee index df9cf242e1..8320849058 100644 --- a/pub/work/src/js/components/SortComponent.coffee +++ b/pub/work/src/js/components/SortComponent.coffee @@ -1,6 +1,6 @@ recl = React.createClass rece = React.createElement -[div,h1,button,label] = [React.DOM.div,React.DOM.h1,React.DOM.button,React.DOM.label] +{div,h1,button,label} = React.DOM module.exports = recl _onClick: (e) -> @@ -22,4 +22,4 @@ module.exports = recl (label {}, k) (div {className:'caret ib'}, '') ]) - ) \ No newline at end of file + ) diff --git a/pub/work/src/js/components/WorkComponent.coffee b/pub/work/src/js/components/WorkComponent.coffee index 3f18bbcb00..8f2c093c1f 100644 --- a/pub/work/src/js/components/WorkComponent.coffee +++ b/pub/work/src/js/components/WorkComponent.coffee @@ -1,6 +1,6 @@ recl = React.createClass rece = React.createElement -[div,h1] = [React.DOM.div,React.DOM.h1] +{div,h1} = React.DOM ListComponent = require './ListComponent.coffee' @@ -9,4 +9,4 @@ module.exports = recl (div {}, [ (h1 {className:'leader'}, "Work") (rece(ListComponent,{list:'upcoming'})) - ]) \ No newline at end of file + ]) diff --git a/pub/work/src/js/main.js b/pub/work/src/js/main.js index 4cff94f145..2a96b1b780 100644 --- a/pub/work/src/js/main.js +++ b/pub/work/src/js/main.js @@ -6,22 +6,25 @@ Dispatcher = require('../dispatcher/Dispatcher.coffee'); Persistence = require('../persistence/Persistence.coffee'); module.exports = { - newItem: function(index, list) { - var item; + newItem: function(index, _item) { + var item, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7; + if (_item == null) { + _item = {}; + } item = { id: window.util.uuid32(), version: 0, - "date-created": Date.now(), - "date-modified": Date.now(), - "date-due": null, - done: null, owner: window.urb.ship, - status: 'announced', - tags: [], - title: '', - description: '', - discussion: [], - audience: [window.util.talk.mainStationPath(window.urb.ship)] + date_created: Date.now(), + date_modified: Date.now(), + date_due: (ref = _item.date_due) != null ? ref : null, + done: (ref1 = _item.done) != null ? ref1 : null, + status: (ref2 = _item.status) != null ? ref2 : 'announced', + tags: (ref3 = _item.tags) != null ? ref3 : [], + title: (ref4 = _item.title) != null ? ref4 : '', + description: (ref5 = _item.description) != null ? ref5 : '', + discussion: (ref6 = _item.discussion) != null ? ref6 : [], + audience: (ref7 = _item.audience) != null ? ref7 : [window.util.talk.mainStationPath(window.urb.ship)] }; Persistence.put({ "new": item @@ -127,7 +130,7 @@ recl = React.createClass; rece = React.createElement; -ref = [React.DOM.div, React.DOM.h1, React.DOM.label], div = ref[0], h1 = ref[1], label = ref[2]; +ref = React.DOM, div = ref.div, h1 = ref.h1, label = ref.label; module.exports = recl({ _onKeyDown: function(e) { @@ -211,12 +214,12 @@ var WorkActions, div, recl, ref, textarea; recl = React.createClass; -ref = [React.DOM.div, React.DOM.textarea], div = ref[0], textarea = ref[1]; +ref = React.DOM, div = ref.div, textarea = ref.textarea; WorkActions = require('../actions/WorkActions.coffee'); module.exports = recl({ - _dragStart: function(e) { + onDragStart: function(e) { var $t; $t = $(e.target); this.dragged = $t.closest('.item'); @@ -224,10 +227,10 @@ module.exports = recl({ e.dataTransfer.setData('text/html', e.currentTarget); return this.props._dragStart(e, this); }, - _dragEnd: function(e) { + onDragEnd: function(e) { return this.props._dragEnd(e, this); }, - _keyDown: function(e) { + onKeyDown: function(e) { var kc; this.props._keyDown(e, this); kc = e.keyCode; @@ -253,7 +256,7 @@ module.exports = recl({ if ($el[0].tagName === 'TEXTAREA') { return $el.val(); } else { - if (key === 'date-due') { + if (key === 'date_due') { d = $el.text().slice(1).replace(/\./g, "-"); if (d.length < 8) { return NaN; @@ -277,7 +280,7 @@ module.exports = recl({ if (key === 'tags' || key === 'audience') { return _.xor(l, n).length > 0; } - if (key === 'date-due') { + if (key === 'date_due') { return l !== new Date(n); } return l !== n; @@ -285,7 +288,7 @@ module.exports = recl({ validateField: function($t, id, key, val) { var i, valid; valid = 1; - if (key === 'date-due') { + if (key === 'date_due') { if (isNaN(val)) { valid = 0; } @@ -309,7 +312,7 @@ module.exports = recl({ } return valid; }, - _keyUp: function(e) { + onKeyUp: function(e) { var $t, id, key, val, ver; $t = $(e.target).closest('.field'); id = $t.closest('.item').attr('data-id'); @@ -330,7 +333,7 @@ module.exports = recl({ }, 1000); } }, - _focus: function(e) { + onFocus: function(e) { return this.props._focus(e, this); }, _markDone: function(e) { @@ -367,6 +370,28 @@ module.exports = recl({ expand: false }; }, + renderField: function(key, props, format) { + var _props, className, ref1; + if (format == null) { + format = _.identity; + } + _props = _.extend({}, props, { + contentEditable: true, + className: 'input ib' + }); + className = ((ref1 = props.className) != null ? ref1 : key) + " field ib"; + return div({ + className: className, + 'data-key': key + }, div(_props, format(this.props.item[key]))); + }, + renderTopField: function(key, props, format) { + var _props, ref1; + _props = _.extend({ + className: ((ref1 = props.className) != null ? ref1 : key) + " top" + }, props); + return this.renderField(key, _props, format); + }, render: function() { var itemClass, k, owner, ref1; itemClass = 'item'; @@ -396,55 +421,29 @@ module.exports = recl({ draggable: true, 'data-id': this.props.item.id, 'data-index': this.props.index, - onDragStart: this._dragStart, - onDragEnd: this._dragEnd + onDragStart: this.onDragStart, + onDragEnd: this.onDragEnd }, [ div({ className: 'owner ib', 'data-key': 'owner' - }, owner), div({ - className: 'audience field ib', - 'data-key': 'audience' - }, [ - div({ - contentEditable: true, - className: 'input ib' - }, this.formatAudience(this.props.item.audience)) - ]), div({ + }, owner), this.renderField('audience', {}, this.formatAudience), div({ className: 'sort ib top' }, this.props.item.sort), div({ className: 'done ib', onClick: this._markDone - }, ''), div({ - className: 'title ib top field', - 'data-key': 'title' - }, [ - div({ - contentEditable: true, - onFocus: this._focus, - onKeyDown: this._keyDown, - onKeyUp: this._keyUp, - className: 'input ib' - }, this.props.item.title) - ]), div({ - className: 'date ib top field', - 'data-key': 'date-due' - }, [ - div({ - contentEditable: true, - className: 'input ib', - onKeyUp: this._keyUp - }, this.formatDate(this.props.item['date-due'])) - ]), div({ - className: 'tags ib top field', - 'data-key': 'tags' - }, [ - div({ - contentEditable: true, - className: 'input ib', - onKeyUp: this._keyUp - }, this.props.item.tags.join(" ")) - ]), div({ + }, ''), this.renderTopField('title', { + onFocus: this.onFocus, + onKeyDown: this.onKeyDown, + onKeyUp: this.onKeyUp + }), this.renderTopField('date_due', { + onKeyUp: this.onKeyUp, + className: 'date' + }, this.formatDate), this.renderTopField('tags', { + onKeyUp: this.onKeyUp + }, function(tags) { + return tags.join(" "); + }), div({ className: 'expand ib', onClick: (function(_this) { return function(e) { @@ -453,19 +452,11 @@ module.exports = recl({ }); }; })(this) - }, [ - div({ - className: 'caret left' - }, "") - ]), div({ - className: 'description field', - 'data-key': 'description' - }, [ - textarea({ - className: 'input ib', - onKeyUp: this._keyUp - }, this.props.item.description) - ]), div({ + }, div({ + className: 'caret left' + }, "")), this.renderField('description', { + onKeyUp: this.onKeyUp + }), div({ className: "hr" }, ""), div({ className: "discussion" @@ -519,7 +510,7 @@ recl = React.createClass; rece = React.createElement; -ref = [React.DOM.div, React.DOM.h1, React.DOM.input, React.DOM.textarea], div = ref[0], h1 = ref[1], input = ref[2], textarea = ref[3]; +ref = React.DOM, div = ref.div, h1 = ref.h1, input = ref.input, textarea = ref.textarea; WorkStore = require('../stores/WorkStore.coffee'); @@ -734,7 +725,7 @@ recl = React.createClass; rece = React.createElement; -ref = [React.DOM.div, React.DOM.h1, React.DOM.input, React.DOM.textarea], div = ref[0], h1 = ref[1], input = ref[2], textarea = ref[3]; +ref = React.DOM, div = ref.div, h1 = ref.h1, input = ref.input, textarea = ref.textarea; module.exports = recl({ render: function() { @@ -753,7 +744,7 @@ recl = React.createClass; rece = React.createElement; -ref = [React.DOM.div, React.DOM.h1, React.DOM.button, React.DOM.label], div = ref[0], h1 = ref[1], button = ref[2], label = ref[3]; +ref = React.DOM, div = ref.div, h1 = ref.h1, button = ref.button, label = ref.label; module.exports = recl({ _onClick: function(e) { @@ -799,7 +790,7 @@ recl = React.createClass; rece = React.createElement; -ref = [React.DOM.div, React.DOM.h1], div = ref[0], h1 = ref[1]; +ref = React.DOM, div = ref.div, h1 = ref.h1; ListComponent = require('./ListComponent.coffee'); @@ -1264,9 +1255,9 @@ _list = [ id: "0v0", version: 0, sort: 0, - "date-created": new Date('2015-8-18'), - "date-modified": new Date('2015-8-18'), - "date-due": new Date('2015-8-18'), + date_created: new Date('2015-8-18'), + date_modified: new Date('2015-8-18'), + date_due: new Date('2015-8-18'), owner: "~zod", audience: ["~doznec/urbit-meta", "~doznec/tlon"], status: "working", @@ -1284,9 +1275,9 @@ _list = [ id: "0v1", version: 0, sort: 1, - "date-created": new Date('2015-8-18'), - "date-modified": new Date('2015-8-18'), - "date-due": null, + date_created: new Date('2015-8-18'), + date_modified: new Date('2015-8-18'), + date_due: null, owner: null, audience: ["~doznec/tlon"], status: "working", @@ -1298,9 +1289,9 @@ _list = [ id: "0v2", version: 0, sort: 2, - "date-created": new Date('2015-8-18'), - "date-modified": new Date('2015-8-18'), - "date-due": null, + date_created: new Date('2015-8-18'), + date_modified: new Date('2015-8-18'), + date_due: null, owner: "~talsur-todres", audience: ["~doznec/tlon"], status: "working", @@ -1323,7 +1314,7 @@ _filters = { _sorts = { title: 0, owner: 0, - "date-due": 0, + date_due: 0, sort: 0 }; @@ -1431,14 +1422,23 @@ WorkStore = assign({}, EventEmitter.prototype, { _item = _.extend({ sort: index }, item); - _item["date-modified"] = new Date(item["date-modified"]); - _item["date-created"] = new Date(item["date-created"]); - if (item["date-due"] != null) { - _item["date-due"] = new Date(item["date-due"]); + _item.date_modified = new Date(item.date_modified); + _item.date_created = new Date(item.date_created); + if (item.date_due != null) { + _item.date_due = new Date(item.date_due); } if (item.done != null) { _item.done = new Date(item.done); } + _item.discussion = item.discussion.map(function(arg) { + var body, date, ship; + ship = arg.ship, body = arg.body, date = arg.date; + return { + ship: ship, + body: body, + date: new Date(date) + }; + }); return _item; }, newItem: function(arg) { diff --git a/pub/work/src/js/stores/WorkStore.coffee b/pub/work/src/js/stores/WorkStore.coffee index 25007bee51..0a7cb05c47 100644 --- a/pub/work/src/js/stores/WorkStore.coffee +++ b/pub/work/src/js/stores/WorkStore.coffee @@ -6,9 +6,9 @@ _list = [ id:"0v0" version:0 sort:0 - "date-created":new Date('2015-8-18') - "date-modified":new Date('2015-8-18') - "date-due":new Date('2015-8-18') + date_created:new Date('2015-8-18') + date_modified:new Date('2015-8-18') + date_due:new Date('2015-8-18') owner:"~zod" audience:["~doznec/urbit-meta","~doznec/tlon"] status:"working" @@ -26,9 +26,9 @@ _list = [ id:"0v1" version:0 sort:1 - "date-created":new Date('2015-8-18') - "date-modified":new Date('2015-8-18') - "date-due":null + date_created:new Date('2015-8-18') + date_modified:new Date('2015-8-18') + date_due:null owner:null audience:["~doznec/tlon"] status:"working" @@ -40,9 +40,9 @@ _list = [ id:"0v2" version:0 sort:2 - "date-created":new Date('2015-8-18') - "date-modified":new Date('2015-8-18') - "date-due":null + date_created:new Date('2015-8-18') + date_modified:new Date('2015-8-18') + date_due:null owner:"~talsur-todres" audience:["~doznec/tlon"] status:"working" @@ -60,7 +60,7 @@ _filters = _sorts = title:0 owner:0 - "date-due":0 + date_due:0 sort:0 WorkStore = assign {},EventEmitter.prototype,{ @@ -114,10 +114,12 @@ WorkStore = assign {},EventEmitter.prototype,{ itemFromData: (item,index=0)-> _item = _.extend {sort:index}, item - _item["date-modified"] = new Date item["date-modified"] - _item["date-created"] = new Date item["date-created"] - _item["date-due"] = new Date item["date-due"] if item["date-due"]? - _item.done = new Date item.done if item.done? + _item.date_modified = new Date item.date_modified + _item.date_created = new Date item.date_created + _item.date_due = new Date item.date_due if item.date_due? + _item.done = new Date item.done if item.done? + _item.discussion = item.discussion.map ({ship,body,date}) -> + {ship,body,date: new Date date} _item newItem: ({item,index}) -> _list.splice index,0,@itemFromData item,index