2014-11-28 17:49:41 -08:00
storage = require ' core/storage '
deltasLib = require ' core/deltas '
2015-04-08 10:31:38 -07:00
locale = require ' locale/locale '
2014-01-26 14:46:25 -08:00
2014-01-03 10:32:13 -08:00
class CocoModel extends Backbone . Model
2014-07-01 10:16:26 +08:00
idAttribute: ' _id '
2014-01-03 10:32:13 -08:00
loaded: false
loading: false
2014-01-26 14:46:25 -08:00
saveBackups: false
2014-05-22 11:22:52 -07:00
notyErrors: true
2014-01-03 10:32:13 -08:00
@schema: null
2014-07-17 16:22:06 -07:00
initialize: (attributes, options) ->
super ( arguments . . . )
options ? = { }
@ setProjection options . project
2014-01-03 10:32:13 -08:00
if not @ constructor . className
console . error ( " #{ @ } needs a className set. " )
2014-05-19 21:14:27 -07:00
@ on ' sync ' , @ onLoaded , @
2014-04-25 15:31:38 -07:00
@ on ' error ' , @ onError , @
2014-05-30 16:20:20 -07:00
@ on ' add ' , @ onLoaded , @
2014-01-26 14:46:25 -08:00
@saveBackup = _ . debounce ( @ saveBackup , 500 )
2015-01-06 12:40:10 -08:00
@usesVersions = @ schema ( ) ? . properties ? . version ?
2015-01-05 21:57:23 -08:00
backupKey: ->
2015-01-13 09:04:09 -08:00
if @ usesVersions then @ id else @ id # + ':' + @attributes.__v # TODO: doesn't work because __v doesn't actually increment. #2061
# if fixed, RevertModal will also need the fix
2014-08-25 15:39:47 -07:00
setProjection: (project) ->
2015-04-08 12:00:12 -07:00
# TODO: ends up getting done twice, since the URL is modified and the @project is modified. So don't do this, just set project directly... (?)
2014-08-25 15:39:47 -07:00
return if project is @ project
url = @ getURL ( )
url += ' &project= ' unless /project=/ . test url
url = url . replace ' & ' , ' ? ' unless /\?/ . test url
url = url . replace / project = [ ^ & ] * / , " project= #{ project ? . join ( ' , ' ) or ' ' } "
url = url . replace / [ & ? ] project = & / , ' & ' unless project ? . length
url = url . replace / [ & ? ] project = $ / , ' ' unless project ? . length
@ setURL url
@project = project
2014-02-12 12:41:41 -08:00
2014-01-03 10:32:13 -08:00
type: ->
@ constructor . className
2014-04-13 14:48:36 -07:00
2014-04-11 21:11:52 -07:00
clone: (withChanges=true) ->
# Backbone does not support nested documents
clone = super ( )
clone . set ( $ . extend ( true , { } , if withChanges then @ attributes else @ _revertAttributes ) )
clone
2014-05-06 16:58:08 -07:00
2014-12-03 13:32:04 -08:00
onError: (level, jqxhr) ->
2014-04-25 15:31:38 -07:00
@loading = false
2014-05-27 16:33:57 -07:00
@jqxhr = null
2014-12-03 13:32:04 -08:00
if jqxhr . status is 402
2014-12-06 09:35:13 -08:00
Backbone . Mediator . publish ' level:subscription-required ' , { }
2014-01-03 10:32:13 -08:00
2014-01-26 14:46:25 -08:00
onLoaded: ->
2014-01-03 10:32:13 -08:00
@loaded = true
@loading = false
2014-05-27 16:33:57 -07:00
@jqxhr = null
2014-04-12 10:51:02 -07:00
@ loadFromBackup ( )
2014-12-06 09:35:13 -08:00
2014-11-19 14:55:01 -08:00
getCreationDate: -> new Date ( parseInt ( @ id . slice ( 0 , 8 ) , 16 ) * 1000 )
2014-05-21 10:27:38 -07:00
2014-05-02 10:31:20 -07:00
getNormalizedURL: -> " #{ @ urlRoot } / #{ @ id } "
2014-09-01 09:11:10 -07:00
2014-08-23 11:07:52 -07:00
attributesWithDefaults: undefined
2014-09-01 09:11:10 -07:00
2014-08-23 11:07:52 -07:00
get: (attribute, withDefault=false) ->
if withDefault
if @ attributesWithDefaults is undefined then @ buildAttributesWithDefaults ( )
return @ attributesWithDefaults [ attribute ]
else
super ( attribute )
2014-09-01 09:11:10 -07:00
2014-09-02 18:28:02 -07:00
set: (attributes, options) ->
2014-09-16 17:31:00 -07:00
delete @ attributesWithDefaults unless attributes is ' thangs ' # unless attributes is 'thangs': performance optimization for Levels keeping their cache.
2014-05-30 16:20:20 -07:00
inFlux = @ loading or not @ loaded
2014-09-03 10:58:43 -07:00
@ markToRevert ( ) unless inFlux or @ _revertAttributes or @ project or options ? . fromMerge
2014-09-02 18:28:02 -07:00
res = super attributes , options
2014-09-28 14:00:48 -07:00
@ saveBackup ( ) if @ saveBackups and ( not inFlux )
2014-01-26 14:46:25 -08:00
res
2014-02-12 12:41:41 -08:00
2014-08-23 11:07:52 -07:00
buildAttributesWithDefaults: ->
t0 = new Date ( )
clone = $ . extend true , { } , @ attributes
2014-08-28 15:54:05 -07:00
thisTV4 = tv4 . freshApi ( )
thisTV4 . addSchema ( ' # ' , @ schema ( ) )
thisTV4 . addSchema ( ' metaschema ' , require ( ' schemas/metaschema ' ) )
2014-11-29 17:51:32 -08:00
TreemaUtils . populateDefaults ( clone , @ schema ( ) , thisTV4 )
2014-08-23 11:07:52 -07:00
@attributesWithDefaults = clone
2014-10-19 21:56:26 -07:00
duration = new Date ( ) - t0
2014-10-21 20:29:45 -07:00
console . debug " Populated defaults for #{ @ type ( ) } #{ if @ attributes . name then ' ' + @ attributes . name else ' ' } in #{ duration } ms " if duration > 10
2014-08-23 11:07:52 -07:00
2014-03-23 10:29:08 -07:00
loadFromBackup: ->
return unless @ saveBackups
2015-01-05 21:57:23 -08:00
existing = storage . load @ backupKey ( )
2014-03-23 10:29:08 -07:00
if existing
2014-07-01 10:16:26 +08:00
@ set ( existing , { silent: true } )
2015-01-05 21:57:23 -08:00
CocoModel . backedUp [ @ backupKey ( ) ] = @
2014-03-23 10:29:08 -07:00
2014-07-03 17:41:34 -07:00
saveBackup: -> @ saveBackupNow ( )
2014-08-25 15:39:47 -07:00
2014-07-03 17:41:34 -07:00
saveBackupNow: ->
2015-01-05 21:57:23 -08:00
storage . save ( @ backupKey ( ) , @ attributes )
CocoModel . backedUp [ @ backupKey ( ) ] = @
2014-02-12 12:41:41 -08:00
2014-01-26 14:46:25 -08:00
@backedUp = { }
2014-01-03 10:32:13 -08:00
schema: -> return @ constructor . schema
2014-06-24 09:43:14 -07:00
2014-05-30 17:24:53 -07:00
getValidationErrors: ->
2014-09-08 16:03:29 -07:00
# Since Backbone unset only sets things to undefined instead of deleting them, we ignore undefined properties.
definedAttributes = _ . pick @ attributes , (v) -> v isnt undefined
errors = tv4 . validateMultiple ( definedAttributes , @ constructor . schema or { } ) . errors
2014-05-30 17:24:53 -07:00
return errors if errors ? . length
2014-01-03 10:32:13 -08:00
validate: ->
2014-05-30 17:24:53 -07:00
errors = @ getValidationErrors ( )
if errors ? . length
console . debug " Validation failed for #{ @ constructor . className } : ' #{ @ get ( ' name ' ) or @ } ' . "
for error in errors
2014-07-01 10:16:26 +08:00
console . debug " \t " , error . dataPath , ' : ' , error . message
2014-10-21 19:38:57 -07:00
console . trace ? ( )
2014-05-30 17:24:53 -07:00
return errors
2014-06-24 09:43:14 -07:00
2014-01-03 10:32:13 -08:00
save: (attrs, options) ->
options ? = { }
2014-12-01 15:29:12 -08:00
originalOptions = _ . cloneDeep ( options )
2014-05-30 14:41:41 -07:00
options . headers ? = { }
2014-09-08 14:31:52 -07:00
options . headers [ ' X-Current-Path ' ] = document . location ? . pathname ? ' unknown '
2014-01-03 10:32:13 -08:00
success = options . success
2014-05-21 10:27:38 -07:00
error = options . error
options.success = (model, res) =>
2014-12-01 16:09:59 -08:00
@retries = 0
2014-07-01 10:16:26 +08:00
@ trigger ' save:success ' , @
2014-05-21 10:27:38 -07:00
success ( @ , res ) if success
2014-05-30 16:20:20 -07:00
@ markToRevert ( ) if @ _revertAttributes
2014-01-26 14:46:25 -08:00
@ clearBackup ( )
2014-05-24 20:45:53 +02:00
CocoModel . pollAchievements ( )
2014-09-25 00:02:53 -07:00
options.success = options.error = null # So the callbacks can be garbage-collected.
2014-05-21 10:27:38 -07:00
options.error = (model, res) =>
2014-12-01 15:29:12 -08:00
if res . status is 0
2014-12-01 16:09:59 -08:00
@ retries ? = 0
@ retries += 1
if @ retries > 20
msg = ' Your computer or our servers appear to be offline. Please try refreshing. '
noty text: msg , layout: ' center ' , type: ' error ' , killer: true
return
else
msg = $ . i18n . t ' loading_error.connection_failure ' , defaultValue: ' Connection failed. '
2015-03-04 09:00:32 -08:00
try
noty text: msg , layout: ' center ' , type: ' error ' , killer: true , timeout: 3000
catch notyError
console . warn " Couldn ' t even show noty error for " , error , " because " , notyError
2014-12-01 16:09:59 -08:00
return _ . delay ( ( f = => @ save ( attrs , originalOptions ) ) , 3000 )
2014-05-21 10:27:38 -07:00
error ( @ , res ) if error
2014-05-22 11:22:52 -07:00
return unless @ notyErrors
2014-05-21 10:27:38 -07:00
errorMessage = " Error saving #{ @ get ( ' name ' ) ? @ type ( ) } "
2014-09-16 17:31:00 -07:00
console . log ' going to log an error message '
console . warn errorMessage , res . responseJSON
2014-10-01 22:02:52 -07:00
unless webkit ? . messageHandlers # Don't show these notys on iPad
try
2015-01-07 16:02:52 -08:00
noty text: " #{ errorMessage } : #{ res . status } #{ res . statusText } \n #{ res . responseText } " , layout: ' topCenter ' , type: ' error ' , killer: false , timeout: 10000
2014-10-01 22:02:52 -07:00
catch notyError
console . warn " Couldn ' t even show noty error for " , error , " because " , notyError
2014-09-25 00:02:53 -07:00
options.success = options.error = null # So the callbacks can be garbage-collected.
2014-07-01 10:16:26 +08:00
@ trigger ' save ' , @
2014-01-03 10:32:13 -08:00
return super attrs , options
2014-06-24 09:43:14 -07:00
2014-06-10 20:43:25 -07:00
patch: (options) ->
return false unless @ _revertAttributes
options ? = { }
options.patch = true
2014-10-27 16:09:52 -07:00
options.type = ' PUT '
2014-06-24 09:43:14 -07:00
2014-06-10 20:43:25 -07:00
attrs = { _id: @ id }
2014-06-11 14:17:31 -07:00
keys = [ ]
2014-06-10 20:43:25 -07:00
for key in _ . keys @ attributes
unless _ . isEqual @ attributes [ key ] , @ _revertAttributes [ key ]
attrs [ key ] = @ attributes [ key ]
2014-06-11 14:17:31 -07:00
keys . push key
2014-06-24 09:43:14 -07:00
2014-06-11 14:17:31 -07:00
return unless keys . length
console . debug ' Patching ' , @ get ( ' name ' ) or @ , keys
2014-06-10 20:43:25 -07:00
@ save ( attrs , options )
2014-01-03 10:32:13 -08:00
2014-07-17 16:22:06 -07:00
fetch: (options) ->
options ? = { }
options . data ? = { }
options.data.project = @ project . join ( ' , ' ) if @ project
2015-02-12 11:17:23 -08:00
#console.error @constructor.className, @, "fetching with cache?", options.cache, "options", options # Useful for debugging cached IE fetches
2014-07-17 16:22:06 -07:00
@jqxhr = super ( options )
2014-01-03 10:32:13 -08:00
@loading = true
2014-05-02 10:31:20 -07:00
@ jqxhr
2014-01-03 10:32:13 -08:00
2014-05-30 16:20:20 -07:00
markToRevert: ->
2014-03-23 10:00:16 -07:00
if @ type ( ) is ' ThangType '
2014-09-02 17:46:52 -07:00
# Don't deep clone the raw vector data, but do deep clone everything else.
@_revertAttributes = _ . clone @ attributes
for smallProp , value of @ attributes when value and smallProp isnt ' raw '
@ _revertAttributes [ smallProp ] = _ . cloneDeep value
2014-03-23 10:00:16 -07:00
else
2014-03-22 02:21:23 +00:00
@_revertAttributes = $ . extend ( true , { } , @ attributes )
2014-01-03 10:32:13 -08:00
revert: ->
2014-08-26 10:14:36 -07:00
@ clear ( { silent: true } )
2014-01-03 10:32:13 -08:00
@ set ( @ _revertAttributes , { silent: true } ) if @ _revertAttributes
2014-01-26 14:46:25 -08:00
@ clearBackup ( )
2014-02-12 12:41:41 -08:00
2014-01-26 14:46:25 -08:00
clearBackup: ->
2015-01-05 21:57:23 -08:00
storage . remove @ backupKey ( )
2014-01-03 10:32:13 -08:00
hasLocalChanges: ->
2014-05-29 10:48:48 -07:00
@ _revertAttributes and not _ . isEqual @ attributes , @ _revertAttributes
2014-01-03 10:32:13 -08:00
cloneNewMinorVersion: ->
2014-05-06 05:07:34 +02:00
newData = _ . clone @ attributes
2014-04-11 22:33:09 -07:00
clone = new @ constructor ( newData )
clone
2014-01-03 10:32:13 -08:00
cloneNewMajorVersion: ->
clone = @ cloneNewMinorVersion ( )
clone . unset ( ' version ' )
clone
isPublished: ->
2014-09-01 09:11:10 -07:00
for permission in ( @ get ( ' permissions ' , true ) ? [ ] )
2014-01-03 10:32:13 -08:00
return true if permission . target is ' public ' and permission . access is ' read '
false
publish: ->
2014-07-01 10:16:26 +08:00
if @ isPublished ( ) then throw new Error ( ' Can \' t publish what \' s already-published. Can \' t kill what \' s already dead. ' )
2014-09-01 09:11:10 -07:00
@ set ' permissions ' , @ get ( ' permissions ' , true ) . concat ( { access: ' read ' , target: ' public ' } )
2014-01-03 10:32:13 -08:00
@isObjectID: (s) ->
2014-04-11 20:38:34 -07:00
s . length is 24 and s . match ( /[a-f0-9]/gi ) ? . length is 24
2014-01-03 10:32:13 -08:00
2014-03-03 20:41:35 +01:00
hasReadAccess: (actor) ->
# actor is a User object
2014-08-23 11:07:52 -07:00
actor ? = me
2014-04-10 13:09:44 -07:00
return true if actor . isAdmin ( )
2015-02-25 18:41:39 -08:00
return true if actor . isArtisan ( ) and @ editableByArtisans
2014-09-01 09:11:10 -07:00
for permission in ( @ get ( ' permissions ' , true ) ? [ ] )
if permission . target is ' public ' or actor . get ( ' _id ' ) is permission . target
return true if permission . access in [ ' owner ' , ' read ' ]
2014-03-03 20:41:35 +01:00
return false
2014-03-03 21:13:02 +01:00
hasWriteAccess: (actor) ->
# actor is a User object
2014-08-23 11:07:52 -07:00
actor ? = me
2014-04-10 13:09:44 -07:00
return true if actor . isAdmin ( )
2015-02-25 18:41:39 -08:00
return true if actor . isArtisan ( ) and @ editableByArtisans
2014-09-01 09:11:10 -07:00
for permission in ( @ get ( ' permissions ' , true ) ? [ ] )
if permission . target is ' public ' or actor . get ( ' _id ' ) is permission . target
return true if permission . access in [ ' owner ' , ' write ' ]
2014-03-03 20:41:35 +01:00
return false
2014-04-13 14:48:36 -07:00
2014-08-28 10:50:20 -07:00
getOwner: ->
2014-09-01 09:11:10 -07:00
ownerPermission = _ . find @ get ( ' permissions ' , true ) , access: ' owner '
2014-08-28 10:50:20 -07:00
ownerPermission ? . target
2014-04-09 16:09:35 -07:00
getDelta: ->
2014-04-11 21:11:52 -07:00
differ = deltasLib . makeJSONDiffer ( )
2014-10-27 17:11:48 -07:00
differ . diff ( _ . omit ( @ _revertAttributes , deltasLib . DOC_SKIP_PATHS ) , _ . omit ( @ attributes , deltasLib . DOC_SKIP_PATHS ) )
2014-05-21 10:27:38 -07:00
2014-05-08 10:54:39 -07:00
getDeltaWith: (otherModel) ->
differ = deltasLib . makeJSONDiffer ( )
differ . diff @ attributes , otherModel . attributes
2014-04-13 14:48:36 -07:00
2014-04-11 21:11:52 -07:00
applyDelta: (delta) ->
newAttributes = $ . extend ( true , { } , @ attributes )
2014-06-24 09:43:14 -07:00
try
jsondiffpatch . patch newAttributes , delta
catch error
2014-07-04 20:45:42 -07:00
console . error ' Error applying delta \n ' , JSON . stringify ( delta , null , ' \t ' ) , ' \n \n to attributes \n \n ' , newAttributes
2014-06-24 17:25:01 -04:00
return false
2014-08-11 18:47:00 -07:00
for key , value of newAttributes
delete newAttributes [ key ] if _ . isEqual value , @ attributes [ key ]
2014-08-25 15:39:47 -07:00
2014-04-11 21:11:52 -07:00
@ set newAttributes
2014-06-24 17:25:01 -04:00
return true
2014-04-13 14:48:36 -07:00
2014-04-09 19:07:44 -07:00
getExpandedDelta: ->
delta = @ getDelta ( )
2014-04-12 15:16:42 +05:30
deltasLib . expandDelta ( delta , @ _revertAttributes , @ schema ( ) )
2014-04-13 14:48:36 -07:00
2014-05-08 10:54:39 -07:00
getExpandedDeltaWith: (otherModel) ->
delta = @ getDeltaWith ( otherModel )
deltasLib . expandDelta ( delta , @ attributes , @ schema ( ) )
2014-04-15 15:09:36 -07:00
watch: (doWatch=true) ->
2014-07-01 10:16:26 +08:00
$ . ajax ( " #{ @ urlRoot } / #{ @ id } /watch " , { type: ' PUT ' , data: { on : doWatch } } )
2014-04-16 11:02:40 -07:00
@watching = -> doWatch
2014-04-22 11:11:08 -07:00
2014-04-15 15:09:36 -07:00
watching: ->
2014-04-16 11:02:40 -07:00
return me . id in ( @ get ( ' watchers ' ) or [ ] )
2014-05-06 16:58:08 -07:00
2014-04-22 17:56:41 -07:00
populateI18N: (data, schema, path='') ->
# TODO: Better schema/json walking
sum = 0
data ? = $ . extend true , { } , @ attributes
schema ? = @ schema ( ) or { }
2014-10-27 17:11:48 -07:00
addedI18N = false
2014-04-22 17:56:41 -07:00
if schema . properties ? . i18n and _ . isPlainObject ( data ) and not data . i18n ?
2014-10-28 11:18:36 -07:00
data.i18n = { ' - ' : { ' - ' : ' - ' } } # mongoose doesn't work with empty objects
2014-04-22 17:56:41 -07:00
sum += 1
2014-10-27 17:11:48 -07:00
addedI18N = true
2014-05-06 16:58:08 -07:00
2014-04-22 17:56:41 -07:00
if _ . isPlainObject data
for key , value of data
numChanged = 0
numChanged = @ populateI18N ( value , childSchema , path + ' / ' + key ) if childSchema = schema . properties ? [ key ]
if numChanged and not path # should only do this for the root object
@ set key , value
sum += numChanged
2014-05-06 16:58:08 -07:00
2014-04-22 17:56:41 -07:00
if schema . items and _ . isArray data
sum += @ populateI18N ( value , schema . items , path + ' / ' + index ) for value , index in data
2014-05-06 16:58:08 -07:00
2014-10-27 17:11:48 -07:00
@ set ( ' i18n ' , data . i18n ) if addedI18N and not path # need special case for root i18n
2014-10-17 12:12:06 -04:00
@ updateI18NCoverage ( )
2014-04-22 17:56:41 -07:00
sum
2014-03-03 20:41:35 +01:00
2014-04-25 19:11:32 -07:00
@getReferencedModel: (data, schema) ->
return null unless schema . links ?
2014-07-01 10:16:26 +08:00
linkObject = _ . find schema . links , rel: ' db '
2014-04-25 19:11:32 -07:00
return null unless linkObject
2014-07-01 10:16:26 +08:00
return null if linkObject . href . match ( ' thang.type ' ) and not @ isObjectID ( data ) # Skip loading hardcoded Thang Types for now (TODO)
2014-04-25 19:11:32 -07:00
# not fully extensible, but we can worry about that later
link = linkObject . href
link = link . replace ( ' {(original)} ' , data . original )
link = link . replace ( ' {(majorVersion)} ' , ' ' + ( data . majorVersion ? 0 ) )
link = link . replace ( ' {($)} ' , data )
@ getOrMakeModelFromLink ( link )
@getOrMakeModelFromLink: (link) ->
makeUrlFunc = (url) -> -> url
modelUrl = link . split ( ' / ' ) [ 2 ]
modelModule = _ . string . classify ( modelUrl )
modulePath = " models/ #{ modelModule } "
try
Model = require modulePath
catch e
console . error ' could not load model from link path ' , link , ' using path ' , modulePath
return
model = new Model ( )
model.url = makeUrlFunc ( link )
return model
2014-05-06 16:58:08 -07:00
2014-04-26 12:54:03 -07:00
setURL: (url) ->
makeURLFunc = (u) -> -> u
@url = makeURLFunc ( url )
@
2014-05-06 16:58:08 -07:00
2014-04-26 12:54:03 -07:00
getURL: ->
return if _ . isString @ url then @ url else @ url ( )
2014-05-06 16:58:08 -07:00
2014-05-24 20:45:53 +02:00
@pollAchievements: ->
2014-11-28 17:49:41 -08:00
CocoCollection = require ' collections/CocoCollection '
2015-01-08 11:57:24 -08:00
EarnedAchievement = require ' models/EarnedAchievement '
2014-12-06 09:35:13 -08:00
2014-11-28 17:49:41 -08:00
class NewAchievementCollection extends CocoCollection
2015-01-08 11:57:24 -08:00
model: EarnedAchievement
2014-11-28 17:49:41 -08:00
initialize: ( me = require ( ' core/auth ' ) . me ) ->
@url = " /db/user/ #{ me . id } /achievements?notified=false "
2014-05-24 20:45:53 +02:00
achievements = new NewAchievementCollection
2014-07-30 22:23:43 +02:00
achievements . fetch
2014-05-24 20:45:53 +02:00
success: (collection) ->
2015-02-12 11:17:23 -08:00
me . fetch ( cache: false , success: -> Backbone . Mediator . publish ( ' achievements:new ' , earnedAchievements: collection ) ) unless _ . isEmpty ( collection . models )
2014-08-07 22:03:00 +02:00
error: ->
console . error ' Miserably failed to fetch unnotified achievements ' , arguments
2015-02-11 13:12:42 -08:00
cache: false
2014-05-24 20:45:53 +02:00
2014-10-17 10:11:26 -04:00
CocoModel.pollAchievements = _ . debounce CocoModel . pollAchievements , 500
2014-10-21 13:57:49 -07:00
2014-10-17 10:11:26 -04:00
#- Internationalization
updateI18NCoverage: ->
2015-01-05 15:33:05 -08:00
langCodeArrays = [ ]
pathToData = { }
TreemaUtils . walk ( @ attributes , @ schema ( ) , null , (path, data, workingSchema) ->
# Store parent data for the next block...
if data ? . i18n
pathToData [ path ] = data
2015-01-05 21:57:23 -08:00
2015-01-05 15:33:05 -08:00
if _ . string . endsWith path , ' i18n '
i18n = data
2015-01-05 21:57:23 -08:00
2015-01-05 15:33:05 -08:00
# grab the parent data
parentPath = path [ 0 . . . - 5 ]
parentData = pathToData [ parentPath ]
2015-01-05 21:57:23 -08:00
2015-01-05 15:33:05 -08:00
# use it to determine what properties actually need to be translated
props = workingSchema . props or [ ]
props = ( prop for prop in props when parentData [ prop ] )
2015-04-08 10:31:38 -07:00
#unless props.length
# console.log 'props is', props, 'path is', path, 'data is', data, 'parentData is', parentData, 'workingSchema is', workingSchema
# langCodeArrays.push _.without _.keys(locale), 'update' # Every language has covered a path with no properties to be translated.
# return
return if ' additionalProperties ' of i18n # Workaround for #2630: Programmable is weird
2015-01-05 21:57:23 -08:00
2015-01-05 15:33:05 -08:00
# get a list of lang codes where its object has keys for every prop to be translated
coverage = _ . filter ( _ . keys ( i18n ) , (langCode) ->
translations = i18n [ langCode ]
_ . all ( ( translations [ prop ] for prop in props ) )
)
2015-04-08 10:31:38 -07:00
#console.log 'got coverage', coverage, 'for', path, props, workingSchema, parentData
2015-01-05 15:33:05 -08:00
langCodeArrays . push coverage
)
2015-01-05 21:57:23 -08:00
2015-01-05 15:33:05 -08:00
return unless langCodeArrays . length
# language codes that are covered for every i18n object are fully covered
overallCoverage = _ . intersection ( langCodeArrays . . . )
@ set ( ' i18nCoverage ' , overallCoverage )
2014-05-24 20:45:53 +02:00
2014-01-03 10:32:13 -08:00
module.exports = CocoModel