qiprofile
Version:
Quantitative Imaging Profile ( QiPr) web application
229 lines (179 loc) • 6.92 kB
text/coffeescript
define ['angular', 'moment', 'underscore.string', 'roman', 'helpers',
'demographics', 'tnm', 'imageSequence'],
(ng, moment, _s, roman) ->
filters = ng.module 'qiprofile.filters',
['qiprofile.helpers', 'qiprofile.demographics',
'qiprofile.tnm', 'qiprofile.imagesequence']
filters.filter 'capitalize', ->
(s) -> if s? then _s.capitalize(s) else s
filters.filter 'underscore', ->
(s) -> if s? then _s.underscored(s) else s
filters.filter 'romanize', ['StringHelper', (StringHelper) ->
# @param value the input number or string
# @returns a string with the leading digit sequence converted
# to a roman numeral
(value) ->
if value? then value.toString().replace(/^\d+/, roman.romanize) else value
]
filters.filter 'moment', ->
(date) ->
# Preferably, every REST date string is already converted
# to a moment in the router, but convert a string here just
# in case.
date = DateHelper.asMoment(date) if _.isString(date)
if date? then date.format('MM/DD/YYYY') else date
filters.filter 'notSpecified', ->
# @param value the input value
# @throws 'Not Specified' if the value is null,
# otherwise the input value
(value) ->
if value? then value else 'Not Specified'
filters.filter 'relativeDifference', ->
(objects, index, property=null) ->
evaluate = (object, property) ->
apply = (object, property) ->
if property then object[property] else object
props = property.split('.')
_.reduce(props, apply, object)
current = objects[index]
if index
previous = objects[index - 1]
prevValue = evaluate(previous, property)
currValue = evaluate(current, property)
(currValue - prevValue) / prevValue
filters.filter 'percent', ->
(value) -> if value? then value * 100 else value
filters.filter 'percentRounded', ->
(value) -> Math.round(value * 100) if value?
filters.filter 'imageContainerTitle', ->
# If the image sequence name ends with _reg, then it is a registation.
# Otherwise, it is a scan.
(value) ->
if value.startsWith('reg')
'Registration ' + value
else
_s.capitalize(value) + ' scan'
# Returns the string representation of the given input value as follows:
# * true => 'True'
# * false => 'False'
# * null or undefined => 'Not Specified'
#
# @param value the boolean or null input
# @param trueStr the true conversion
# @param falseStr the false conversion
# @returns the string representation
# @throws TypeError if the value is not boolean, null or undefined
booleanFilter = (value, trueStr='True', falseStr='False') ->
if value == true
trueStr
else if value == false
falseStr
else if not value?
'Not Specified'
else
throw new TypeError("The input value is not boolean, null or" +
" undefined: #{ value }")
filters.filter 'boolean', ->
# Returns the string representation of the given input value as follows:
# * true => 'True'
# * false => 'False'
# * null or undefined => 'Not Specified'
#
# @param value the boolean or null input
# @returns the string representation
# @throws TypeError if the value is not boolean, null or undefined
(value) ->
booleanFilter(value)
filters.filter 'presentAbsent', ->
# Returns the string representation of the given input value as follows:
# * true => 'Present'
# * false => 'Absent'
# * null or undefined => 'Not Specified'
#
# @param value the boolean or null input
# @returns the string representation
# @throws TypeError if the value is not boolean, null or undefined
(value) ->
booleanFilter(value, 'Present', 'Absent')
filters.filter 'positiveNegative', ->
# Returns the string representation of the given input value as follows:
# * true => 'Positive'
# * false => 'Negative'
# * null or undefined => 'Not Specified'
#
# @param value the boolean or null input
# @returns the string representation
# @throws TypeError if the value is not boolean, null or undefined
(value) ->
booleanFilter(value, 'Positive', 'Negative')
filters.filter 'percentSign', ->
# If there is a value, then append the percent sign to the value.
#
# @param value the input number
# @returns the string with a percent sign, or null if no value
(value) ->
if value? then value.toString().concat('%') else value
filters.filter 'percentRange', ->
# If there is a percent range object, then separate the lower and
# upper values with an en dash.
#
# @param range the range object
# @returns the string representation of the percent range
(range) ->
if range?
start = range.start.value.toString()
stop = range.stop.value.toString()
"#{ start }–#{ stop }"
else
range
filters.filter 'visitDates', ->
(sessions) ->
sess.date() for sess in sessions
filters.filter 'multiVolume', ->
(imageSequences) ->
(seq for seq in imageSequences when seq.isMultiVolume())
filters.filter 'gender', ->
(gender) ->
# Expand a gender code.
if gender is 'F'
'Female'
else if gender is 'M'
'Male'
else
gender
filters.filter 'age', ['DateHelper', (DateHelper) ->
(birthDate) ->
# July 7 of this year.
nowish = DateHelper.anonymize(moment())
# The year difference from the birth date.
nowish.diff(birthDate, 'years')
]
filters.filter 'races', ['Race', (Race) ->
(races) ->
dspValues =
Race.toDisplayValue(race) for race in races
dspValues.join(', ')
]
filters.filter 'ethnicity', ['Ethnicity', (Ethnicity) ->
(ethnicity) ->
Ethnicity.toDisplayValue(ethnicity)
]
filters.filter 'tnmSize', ['TNM', (TNM) ->
(size) ->
TNM.formatSize(size)
]
filters.filter 'tnmStage', ['TNM', (TNM) ->
(tnm) ->
TNM.stage(tnm)
]
filters.filter 'breastRecurrenceScore', ['Breast', (Breast) ->
(assay) ->
Breast.recurrenceScore(assay)
]
# @returns [<Saggital> ][<Coronal> ]<Body Part>
filters.filter 'sarcomaTumorLocation', ->
# The REST histology fields.
fields = ['saggitalLocation', 'coronalLocation', 'bodyPart']
(histology) ->
words = (histology[prop] for prop in fields when histology[prop])
words.join(' ')