Added a delta subview for displaying deltas of schema'd data.

This commit is contained in:
Scott Erickson 2014-04-09 16:09:35 -07:00
parent 721648dadf
commit f2d21b960f
6 changed files with 211 additions and 1 deletions

89
app/lib/deltas.coffee Normal file
View file

@ -0,0 +1,89 @@
# path: an array of indexes to navigate into a JSON object
# left:
module.exports.interpretDelta = (delta, path, left, schema) ->
# takes a single delta and converts into an object that can be
# easily formatted into something human readable.
betterDelta = { action:'???', delta: delta }
betterPath = []
parentLeft = left
parentSchema = schema
for key in path
# TODO: A smarter way of getting child schemas
childSchema = parentSchema?.items or parentSchema?.properties?[key] or {}
childLeft = parentLeft?[key]
betterKey = null
betterKey ?= childLeft.name or childLeft.id if childLeft
betterKey ?= "#{childSchema.title} ##{key+1}" if childSchema.title and _.isNumber(key)
betterKey ?= "#{childSchema.title}" if childSchema.title
betterKey ?= _.string.titleize key
betterPath.push betterKey
parentLeft = childLeft
parentSchema = childSchema
betterDelta.path = betterPath.join(' :: ')
betterDelta.schema = childSchema
betterDelta.left = childLeft
betterDelta.right = jsondiffpatch.patch childLeft, delta
if _.isArray(delta) and delta.length is 1
betterDelta.action = 'added'
betterDelta.newValue = delta[0]
if _.isArray(delta) and delta.length is 2
betterDelta.action = 'modified'
betterDelta.oldValue = delta[0]
betterDelta.newValue = delta[1]
if _.isArray(delta) and delta.length is 3 and delta[1] is 0 and delta[2] is 0
betterDelta.action = 'deleted'
betterDelta.oldValue = delta[0]
if _.isPlainObject(delta) and delta._t is 'a'
betterDelta.action = 'modified-array'
if _.isPlainObject(delta) and delta._t isnt 'a'
betterDelta.action = 'modified-object'
if _.isArray(delta) and delta.length is 3 and delta[1] is 0 and delta[2] is 3
betterDelta.action = 'moved-index'
betterDelta.destinationIndex = delta[1]
if _.isArray(delta) and delta.length is 3 and delta[1] is 0 and delta[2] is 2
betterDelta.action = 'text-diff'
betterDelta.unidiff = delta[0]
left = betterDelta.left.trim().split('\n')
right = betterDelta.right.trim().split('\n')
shifted = popped = false
while left.length > 5 and right.length > 5 and left[0] is right[0] and left[1] is right[1]
left.shift()
right.shift()
shifted = true
while left.length > 5 and right.length > 5 and left[left.length-1] is right[right.length-1] and left[left.length-2] is right[right.length-2]
left.pop()
right.pop()
popped = true
left.push('...') and right.push('...') if popped
left.unshift('...') and right.unshift('...') if shifted
betterDelta.trimmedLeft = left.join('\n')
betterDelta.trimmedRight = right.join('\n')
betterDelta
module.exports.flattenDelta = flattenDelta = (delta, path=null) ->
# takes a single delta and returns an array of deltas
path ?= []
return [{path:path, delta:delta}] if _.isArray delta
results = []
affectingArray = delta._t is 'a'
for index, childDelta of delta
continue if index is '_t'
index = parseInt(index.replace('_', '')) if affectingArray
results = results.concat flattenDelta(childDelta, path.concat([index]))
results

View file

@ -215,6 +215,11 @@ class CocoModel extends Backbone.Model
return true if permission.access in ['owner', 'write']
return false
getDelta: ->
jsd = jsondiffpatch.create({
objectHash: (obj) -> obj.name || obj.id || obj._id || JSON.stringify(_.keys(obj))
})
jsd.diff @_revertAttributes, @attributes
module.exports = CocoModel

View file

@ -0,0 +1,35 @@
#delta-list-view
width: 600px
.panel-heading
font-size: 13px
padding: 4px
.row
padding: 5px 10px
.delta-added
border-color: green
strong
color: green
.panel-heading
background-color: lighten(green, 70%)
.delta-modified
border-color: darkgoldenrod
strong
color: darkgoldenrod
.panel-heading
background-color: lighten(darkgoldenrod, 40%)
.delta-text-diff
border-color: blue
strong
color: blue
.panel-heading
background-color: lighten(blue, 45%)
.delta-deleted
border-color: red
strong
color: red
.panel-heading
background-color: lighten(red, 42%)

View file

@ -0,0 +1,35 @@
- var i = 0
.panel-group#accordion
for delta in deltas
.delta.panel.panel-default(class='delta-'+delta.action)
.panel-heading
if delta.action === 'added'
strong(data-i18n="delta.added") Added
if delta.action === 'modified'
strong(data-i18n="delta.modified") Modified
if delta.action === 'deleted'
strong(data-i18n="delta.deleted") Deleted
if delta.action === 'moved-index'
strong(data-i18n="delta.modified_array") Moved Index
if delta.action === 'text-diff'
strong(data-i18n="delta.text_diff") Text Diff
span
a(data-toggle="collapse" data-parent="#accordion" href="#collapse-"+i)
span= delta.path
.panel-collapse.collapse(id="collapse-"+i)
.panel-body.row
if delta.action === 'added'
.new-value.col-md-12= delta.right
if delta.action === 'modified'
.old-value.col-md-6= delta.left
.new-value.col-md-6= delta.right
if delta.action === 'deleted'
.col-md-12
div.old-value= delta.left
if delta.action === 'text-diff'
.col-md-6
pre= delta.trimmedLeft
.col-md-6
pre= delta.trimmedRight
- i += 1

View file

@ -0,0 +1,43 @@
CocoView = require 'views/kinds/CocoView'
template = require 'templates/editor/delta'
deltaLib = require 'lib/deltas'
module.exports = class DeltaListView extends CocoView
id: "delta-list-view"
template: template
constructor: (options) ->
super(options)
@delta = options.delta
@schema = options.schema or {}
@left = options.left
getRenderData: ->
c = super()
deltas = deltaLib.flattenDelta @delta
deltas = (deltaLib.interpretDelta(d.delta, d.path, @left, @schema) for d in deltas)
c.deltas = deltas
@processedDeltas = deltas
c
afterRender: ->
deltas = @$el.find('.delta')
for delta, i in deltas
deltaEl = $(delta)
deltaData = @processedDeltas[i]
console.log 'delta', deltaEl, deltaData
if _.isObject(deltaData.left) and leftEl = deltaEl.find('.old-value')
options =
data: deltaData.left
schema: deltaData.schema
readOnly: true
treema = TreemaNode.make(leftEl, options)
treema.build()
if _.isObject(deltaData.right) and rightEl = deltaEl.find('.old-value')
options =
data: deltaData.right
schema: deltaData.schema
readOnly: true
treema = TreemaNode.make(rightEl, options)
treema.build()

View file

@ -52,6 +52,9 @@
},
"underscore.string": {
"main": "lib/underscore.string.js"
},
"jsondiffpatch": {
"main": ["build/bundle-full.js", "build/formatters.js", "src/formatters/html.css"]
}
}
}