diff --git a/app/client/views/patients/patients.coffee b/app/client/views/patients/patients.coffee index dc5b2ca..963ba4f 100644 --- a/app/client/views/patients/patients.coffee +++ b/app/client/views/patients/patients.coffee @@ -1,365 +1,365 @@ Template.patients.destroyed = -> $(window).off('hashchange') Template.patients.rendered = -> @subscribe("studies", onReady: -> refreshSelectValues()) @subscribe("patients", onReady: -> refreshSelectValues()) @subscribe("therapists", onReady: -> refreshSelectValues()) tmpl = @ @autorun -> selectedStudyIds = Session.get 'selectedStudyIds' if selectedStudyIds? and selectedStudyIds.length > 0 tmpl.subscribe "studyDesignsForStudy", selectedStudyIds, onReady: -> refreshSelectValues() else tmpl.subscribe "studyDesigns", onReady: -> refreshSelectValues() @$('.selectpicker').each -> $(@).selectpicker() #actionsBox: true #only works with multiple now, nobody knows why #liveSearch: true $(window).on('hashchange', hashchange) hashchange() @autorun -> Session.get('selectedStudyIds') Session.get('selectedStudyDesignIds') Session.get('selectedPatientId') Session.get('selectedDesignVisitId') Session.get('selectedQuestionnaireWizzard') refreshSelectValues() refreshUrlParams() Template.patients.helpers studies: -> Studies.find() designs: -> selectedStudyIds = Session.get 'selectedStudyIds' find = {} if selectedStudyIds? find.studyId = {$in: selectedStudyIds} StudyDesigns.find(find).map (design) -> design.study = Studies.findOne(design.studyId) design patients: -> selectedStudyIds = Session.get 'selectedStudyIds' selectedStudyDesignIds = Session.get 'selectedStudyDesignIds' find = {} if selectedStudyIds? find.studyId = {$in: selectedStudyIds} if selectedStudyDesignIds? find.studyDesignId = {$in: selectedStudyDesignIds} Patients.find(find, {sort: {studyId: 1}}) visits: -> selectedStudyIds = Session.get 'selectedStudyIds' selectedStudyDesignIds = Session.get 'selectedStudyDesignIds' selectedPatientId = Session.get 'selectedPatientId' find = {} if selectedStudyIds? find.studyId = {$in: selectedStudyIds} if selectedStudyDesignIds? find._id = {$in: selectedStudyDesignIds} else if selectedPatientId? studyDesignId = Patients.findOne(selectedPatientId).studyDesignId find._id = studyDesignId visits = [] StudyDesigns.find(find).forEach (design) -> design.visits.forEach (v) -> v.design = design v.study = Studies.findOne(design.studyId) visits.push v visits questionnaires: -> selectedPatientId = Session.get 'selectedPatientId' selectedDesignVisitId = Session.get 'selectedDesignVisitId' p = Patients.findOne selectedPatientId if p? d = StudyDesigns.findOne p.studyDesignId if d? v = _.find d.visits, (visit) -> visit._id is selectedDesignVisitId return Questionnaires.find _id: {$in: v.questionnaireIds} return singlePatient: -> Session.get('selectedPatientId')? singleVisit: -> Session.get('selectedPatientId')? and Session.get('selectedDesignVisitId')? patientsTableCursor: -> find = {} selectedStudyIds = Session.get 'selectedStudyIds' if selectedStudyIds? find.studyId = {$in: selectedStudyIds} selectedStudyDesignIds = Session.get 'selectedStudyDesignIds' if selectedStudyDesignIds? find.studyDesignId = {$in: selectedStudyDesignIds} #selectedPatientId = Session.get 'selectedPatientId' #if selectedPatientId? # find._id = selectedPatientId Patients.find(find) patientsRTS: -> useFontAwesome: true rowsPerPage: 100 showFilter: false fields: [ key: 'id', label: "ID" , key: 'hrid', label: "hrid" , key: 'studyId', label: "Study", sort: true fn: (v,o) -> study = o.study() return study.title if study? , key: 'designId', label: "Design" fn: (v,o) -> design = o.studyDesign() return design.title if design? , key: 'therapistId', label: "Therapist" fn: (v,o) -> therapist = o.therapist() return therapist.profile.name if therapist? , key: '', label: "no. sheduled visits" fn: (v,o) -> design = o.studyDesign() return design.visits.length if design? , key: '', label: "no. completed visits" fn: (v,o) -> Visits.find patientId: o._id .count() , key: "createdAt", label: 'created', sortByValue: true fn: (v,o)-> moment(v).fromNow() ] selectedPatient: -> Patients.findOne _id: Session.get('selectedPatientId') Template.patients.events "click #patientsTable table tr": (evt) -> selectPatientId(@_id) return "change #studiesSelect": (evt) -> ids = $('#studiesSelect').val() if ids.indexOf('deselect') > -1 $('#studiesSelect').selectpicker('deselectAll') ids = null Session.set 'selectedDesignVisitId', null Session.set 'selectedPatientId', null Session.set 'selectedStudyIds', ids return "change #designsSelect": (evt) -> ids = $('#designsSelect').val() if ids.indexOf('deselect') > -1 $('#designsSelect').selectpicker('deselectAll') ids = null Session.set 'selectedDesignVisitId', null Session.set 'selectedPatientId', null Session.set 'selectedStudyDesignIds', ids return "change #patientSelect": (evt) -> id = $('#patientSelect').val() ids = null if id is 'deselect' if id is 'deselect' $('#patientSelect').selectpicker('deselectAll') id = null selectPatientId(id) return "change #visitSelect": (evt) -> id = $('#visitSelect').val() if id is 'deselect' $('#visitSelect').selectpicker('deselectAll') id = null Session.set 'selectedDesignVisitId', id return "change #questionnaireSelect": (evt) -> id = $('#questionnaireSelect').val() if id is 'deselect' $('#questionnaireSelect').selectpicker('deselectAll') id = null Session.set 'selectedQuestionnaireId', id return selectPatientId = (id) -> if id? patient = Patients.findOne id studyDesign = StudyDesigns.findOne patient.studyDesignId selectedStudyIds = Session.get('selectedStudyIds') or [] selectedStudyIds.push studyDesign.studyId selectedStudyIds = _.unique selectedStudyIds Session.set 'selectedStudyIds', selectedStudyIds selectedStudyDesignIds = Session.get('selectedStudyDesignIds') or [] selectedStudyDesignIds.push studyDesign._id selectedStudyDesignIds = _.unique selectedStudyDesignIds Session.set 'selectedStudyDesignIds', selectedStudyDesignIds Session.set 'selectedPatientId', id refreshSelectValues = -> Meteor.setTimeout -> $('#studiesSelect').selectpicker('val', Session.get('selectedStudyIds') or null) $('#designsSelect').selectpicker('val', Session.get('selectedStudyDesignIds') or null) $('#patientSelect').selectpicker('val', Session.get('selectedPatientId') or null) $('#visitSelect').selectpicker('val', Session.get('selectedDesignVisitId') or null) $('#questionnaireSelect').selectpicker('val', Session.get('selectedQuestionnaireId') or null) , 100 _hashChangedInternally = false refreshUrlParams = -> newHash = studyIds: Session.get('selectedStudyIds') designIds: Session.get('selectedStudyDesignIds') patientId: Session.get('selectedPatientId') visitId: Session.get('selectedDesignVisitId') questionnaireWizzard: Session.get('selectedQuestionnaireWizzard') #doesn't work because underscore is too old #hash = _.pick hash, (value, key, object) -> value? hash = {} Object.keys(newHash).forEach (key) -> value = newHash[key] hash[key] = value if value? if Object.keys(hash).length > 0 window.location.hash = JSON.stringify hash else window.location.hash = "" return hashchange = -> hash = window.location.hash if hash? and hash.length > 1 hash = JSON.parse hash.slice(1) Session.set 'selectedStudyIds', hash.studyIds Session.set 'selectedStudyDesignIds', hash.designIds Session.set 'selectedPatientId', hash.patientId Session.set 'selectedDesignVisitId', hash.visitId qw = Session.get 'selectedQuestionnaireWizzard' if hash.questionnaireWizzard? if !qw? __showQuestionnaireWizzard hash.questionnaireWizzard else if qw? - Modal.hide 'questionnaireWizzard' + __closeQuestionnaireWizzard() else Session.set 'selectedStudyIds', null Session.set 'selectedStudyDesignIds', null Session.set 'selectedPatientId', null Session.set 'selectedDesignVisitId', null if Session.get('selectedQuestionnaireWizzard')? - Modal.hide 'questionnaireWizzard' + __closeQuestionnaireWizzard() return ################################################ #selects rendering studyOptionTimeout = null refreshStudiesSelect = -> if studyOptionTimeout? Meteor.clearTimeout studyOptionTimeout studyOptionTimeout = Meteor.setTimeout((-> $('#studiesSelect').selectpicker 'refresh' studyOptionTimeout = false return ), 50) return Template.studyOption.rendered = -> refreshStudiesSelect() Template.studyOption.destroyed = -> refreshStudiesSelect() designOptionTimeout = null refreshDesignsSelect = -> if designOptionTimeout? Meteor.clearTimeout designOptionTimeout designOptionTimeout = Meteor.setTimeout((-> $('#designsSelect').selectpicker 'refresh' designOptionTimeout = false return ), 50) return Template.designOption.rendered = -> refreshDesignsSelect() Template.designOption.destroyed = -> refreshDesignsSelect() patientOptionTimeout = null refreshPatientsSelect = -> if patientOptionTimeout? Meteor.clearTimeout patientOptionTimeout patientOptionTimeout = Meteor.setTimeout((-> $('#patientSelect').selectpicker 'refresh' patientOptionTimeout = false return ), 50) return Template.patientOption.rendered = -> refreshPatientsSelect() Template.patientOption.destroyed = -> refreshPatientsSelect() visitOptionTimeout = null refreshVisitsSelect = -> if visitOptionTimeout? Meteor.clearTimeout visitOptionTimeout visitOptionTimeout = Meteor.setTimeout((-> $('#visitSelect').selectpicker 'refresh' visitOptionTimeout = false return ), 50) return Template.visitOption.rendered = -> refreshVisitsSelect() Template.visitOption.destroyed = -> refreshVisitsSelect() questionnaireOptionTimeout = null refreshQuestionnaireSelect = -> if questionnaireOptionTimeout? Meteor.clearTimeout questionnaireOptionTimeout questionnaireOptionTimeout = Meteor.setTimeout((-> $('#questionnaireSelect').selectpicker 'refresh' questionnaireOptionTimeout = false return ), 50) return Template.questionnaireOption.rendered = -> refreshQuestionnaireSelect() Template.questionnaireOption.destroyed = -> refreshQuestionnaireSelect() Template.visitSelect.rendered = -> @$('.selectpicker').each -> $(@).selectpicker() Template.visitSelect.destroyed = -> @$('.selectpicker').each -> $(@).selectpicker('destroy') Template.questionnaireSelect.rendered = -> @$('.selectpicker').each -> $(@).selectpicker() Template.questionnaireSelect.destroyed = -> @$('.selectpicker').each -> $(@).selectpicker('destroy') ################################################ diff --git a/app/client/views/questionnaires/questionnaire_wizzard.coffee b/app/client/views/questionnaires/questionnaire_wizzard.coffee index a370e44..faee9f2 100644 --- a/app/client/views/questionnaires/questionnaire_wizzard.coffee +++ b/app/client/views/questionnaires/questionnaire_wizzard.coffee @@ -1,371 +1,370 @@ @__showQuestionnaireWizzard = (data) -> Session.set 'selectedQuestionnaireWizzard', data Modal.show('questionnaireWizzard', data, keyboard: false) +@__closeQuestionnaireWizzard = -> + if isAFormDirty() + swal { + title: 'Unsaved Changes' + text: "Do you want to save the changes on this page?" + type: 'warning' + showCancelButton: true + confirmButtonText: 'Save and exit' + cancelButtonText: "Exit without saving" + }, (save) -> + if save + submitAllForms('close') + else + Modal.hide('questionnaireWizzard') + else + Modal.hide('questionnaireWizzard') + _numQuestions = new ReactiveVar(0) _numPages = new ReactiveVar(0) _questionIdsForPage = new ReactiveVar({}) _pageIndex = new ReactiveVar(0) _numFormsToSubmit = 0 _readonly = new ReactiveVar(false) _questionnaire = new ReactiveVar(null) _nextQuestionnaire = null _preview = new ReactiveVar(false) isAFormDirty = -> if _readonly.get() or _preview.get() return false isDirty = false $("form").each () -> return if isDirty e = $(@)[0] dirty = formIsDirty(e) isDirty = dirty if dirty isDirty _goto = null submitAllForms = (goto) -> if _readonly.get() or _preview.get() throw new Error("Can't submitAllForms because _readonly == true") _goto = goto numFormsToSubmit = 0 $("form").each () -> e = $(@) classes = e.attr('class') if classes? and classes.indexOf('question') > -1 numFormsToSubmit += 1 _numFormsToSubmit = numFormsToSubmit $("form").each () -> e = $(@) classes = e.attr('class') if classes? and classes.indexOf('question') > -1 e.submit() formSubmitted = -> if (_numFormsToSubmit -= 1) <= 0 if _goto is 'nextPage' nextPage() else if _goto is 'previousPage' previousPage() else if _goto is 'close' Modal.hide('questionnaireWizzard') else if _goto.pageIndex? _pageIndex.set _goto.pageIndex -close = -> - if isAFormDirty() - swal { - title: 'Unsaved Changes' - text: "Do you want to save the changes on this page?" - type: 'warning' - showCancelButton: true - confirmButtonText: 'Save and exit' - cancelButtonText: "Exit without saving" - }, (save) -> - if save - submitAllForms('close') - else - Modal.hide('questionnaireWizzard') - else - Modal.hide('questionnaireWizzard') - - nextPage = -> if _pageIndex.get() is _numPages.get()-1 if _nextQuestionnaire? _pageIndex.set 0 _questionnaire.set _nextQuestionnaire else Modal.hide('questionnaireWizzard') else _pageIndex.set _pageIndex.get()+1 previousPage = -> index = _pageIndex.get() index -= 1 if index > 0 _pageIndex.set index autoformHooks = onSubmit: (insertDoc, updateDoc, currentDoc) -> if _preview.get() or _readonly.get() return insertDoc.visitId = currentDoc.visitId insertDoc.questionId = currentDoc.questionId insertDoc._id = currentDoc._id if currentDoc._id? #console.log "submit questionAutoform" #console.log insertDoc if insertDoc.value? and (!currentDoc.value? or (currentDoc.value? and currentDoc.value isnt insertDoc.value)) Meteor.call "upsertAnswer", insertDoc, (error) -> throwError error if error? formSubmitted() @done() false Template.questionnaireWizzard.created = -> _questionnaire.set @data.questionnaire delete @data.questionnaire if @data.readonly _readonly.set true else _readonly.set false if @data.preview _preview.set true else _preview.set false #close on escape key press $(document).on('keyup.wizzard', (e)-> e.stopPropagation() if e.keyCode is 27 - close() + __closeQuestionnaireWizzard() return ) self = @ @autorun -> self.subscribe("questionsForQuestionnaire", _questionnaire.get()._id) #get manage nextQuestionnaire @autorun -> return if _preview.get() data = Template.currentData() validatedQuestionnaires = data.visit.validatedQuestionnaires i = 0 index = null while i < validatedQuestionnaires.length-1 && index is null q = validatedQuestionnaires[i] if q._id is _questionnaire.get()._id index = i i += 1 if index? and index < validatedQuestionnaires.length-1 _nextQuestionnaire = validatedQuestionnaires[index+1] else _nextQuestionnaire = null #collect autoformIds, count pages @autorun -> count = 0 page = 0 questionIdsForPage = {} didBreakPage = false autoformIds = [] Questions.find questionnaireId: _questionnaire.get()._id , sort: {index: 1} .forEach (q) -> if q.type isnt "description" and q._id isnt "table" and q._id isnt "table_polar" autoformIds.push q._id count += 1 if questionIdsForPage[page]? questionIdsForPage[page].push q._id else questionIdsForPage[page] = [q._id] didBreakPage = false if q.break page += 1 didBreakPage = true page -= 1 if didBreakPage _questionIdsForPage.set questionIdsForPage _numQuestions.set count _numPages.set page+1 _pageIndex.set 0 AutoForm.addHooks(autoformIds, autoformHooks, true) Template.questionnaireWizzard.destroyed = -> $(document).unbind('keyup.wizzard') Session.set('selectedQuestionnaireWizzard', null) Template.questionnaireWizzard.helpers templateGestures: 'swipeleft div': (evt, templateInstance) -> nextQuestion() 'swiperight div': (evt, templateInstance) -> previousQuestion() title: -> _questionnaire.get().title questionsForPage: -> questionIdsForPage = _questionIdsForPage.get()[_pageIndex.get()] Questions.find questionnaireId: _questionnaire.get()._id _id: {$in: questionIdsForPage} , sort: {index: 1} questionnaire: -> _questionnaire.get() answerForQuestion: (visitId, questionId) -> return if _preview.get() Answers.findOne visitId: visitId questionId: questionId readonly: -> _readonly.get() formType: -> if _readonly.get() "disabled" else "normal" answerFormSchema: -> schema = _id: type: String optional: true visitId: type: String optional: true questionId: type: String optional: true value: @question.getSchemaDict() new SimpleSchema(schema) doc: -> return if _preview.get() @answer or visitId: @visit._id questionId: @question._id pages: -> answers = {} questionIds = Questions.find questionnaireId: _questionnaire.get()._id .map (question) -> question._id if !_preview.get() Answers.find visitId: @visit._id questionId: {$in: questionIds} .forEach (answer) -> answers[answer.questionId] = answer activeIndex = _pageIndex.get() questionIdsForPage = _questionIdsForPage.get() pages = [] for i in [0.._numPages.get()-1] css = "" allQuestionsAnsweredInPage = true someQuestionsAnsweredInPage = false Questions.find questionnaireId: _questionnaire.get()._id _id: {$in: questionIdsForPage[i]} .forEach (question) -> return if question.type is "description" answer = answers[question._id] if question.type is "table" or question.type is "table_polar" if !answer? or answer.value.length < question.subquestions.length allQuestionsAnsweredInPage = false if answer? and answer.value.length > 0 someQuestionsAnsweredInPage = true else if !answer? allQuestionsAnsweredInPage = false if allQuestionsAnsweredInPage css = "answered" else if someQuestionsAnsweredInPage css = "answeredPartly" if i is activeIndex css += " active" pages[i] = index: i+1 css: css pages isOnFirstPage: -> _pageIndex.get() is 0 isOnLastPageOfLastQuestionnaire: -> _pageIndex.get() is _numPages.get()-1 and (_preview.get() or _nextQuestionnaire is null) Template.questionnaireWizzard.events "click #next": (evt, tmpl) -> if _readonly.get() or _preview.get() nextPage() else submitAllForms('nextPage') false "click #back": (evt, tmpl) -> if _readonly.get() or _preview.get() previousPage() else submitAllForms('previousPage') false "click .jumpToPage": (evt) -> pageIndex = @index-1 if isAFormDirty() swal { title: 'Unsaved Changes' text: "Do you want to save the changes on this page?" type: 'warning' showCancelButton: true confirmButtonText: 'Save' cancelButtonText: "Don't save" }, (save) -> if save submitAllForms(pageIndex: pageIndex) else _pageIndex.set pageIndex else _pageIndex.set pageIndex false "click #close": (evt) -> - close() + __closeQuestionnaireWizzard() false "submit .questionForm": (evt) -> #table and table_polar if _readonly.get() or _preview.get() return evt.preventDefault() evt.stopPropagation() if @question.type is "description" formSubmitted() return answer = visitId: @visit._id questionId: @question._id value: [] _id: @answer._id if @answer? for subquestion in @question.subquestions inputs = $(evt.target).find("input[data-subquestion_code=#{subquestion.code}]:checked") if @question.selectionMode is "multi" values = [] inputs.each -> input = $(@) values.push input.data('choice_value').toString() if values.length > 0 answer.value.push code: subquestion.code value: values else #if @question.selectionMode is "single" if inputs.length > 1 throw new Meteor.Error('error when processing the values: single selection got multiple values.') else if inputs.length is 1 value = inputs.first().data('choice_value').toString() answer.value.push code: subquestion.code value: value if answer.value.length > 0 Meteor.call "upsertAnswer", answer, (error) -> throwError error if error? formSubmitted() else formSubmitted() false