diff --git a/app/client/views/studies/edit_study_designs.coffee b/app/client/views/studies/edit_study_designs.coffee index 2e1ef38..a2df407 100644 --- a/app/client/views/studies/edit_study_designs.coffee +++ b/app/client/views/studies/edit_study_designs.coffee @@ -1,147 +1,155 @@ listQuestionnaireIds = new ReactiveVar([]) listRecordPhysicalData = new ReactiveVar(false) remainingQuestionnaires = (design) -> qIds = design.questionnaireIds or [] qIds = _.union(qIds, (listQuestionnaireIds.get() or []) ) Questionnaires.find _id: {$nin: qIds} Template.editStudyDesigns.helpers designs: -> StudyDesigns.find studyId: @_id, sort: {createdAt: 1} #this design=design titleEO: -> design = @design value: design.title emptytext: "no title" success: (response, newVal) -> StudyDesigns.update design._id, $set: {title: newVal} return #this design=design hasRemainingQuestionnaires: -> remainingQuestionnaires(@design).count() #this design=design remainingQuestionnaires: -> remainingQuestionnaires(@design) #this design=design questionnaires: -> qIds = @design.questionnaireIds or [] qIds = _.union(qIds, (listQuestionnaireIds.get() or []) ) Questionnaires.find _id: {$in: qIds} listRecordPhysicalData: -> @design.recordPhysicalData || listRecordPhysicalData.get() #this design=design visits: -> @design.visits.sort (a, b)-> a.index - b.index prevDay = 0 #augment visits #http://stackoverflow.com/questions/13789622/accessing-parent-context-in-meteor-templates-and-template-helpers @design.visits.map (v)-> if v.day? daysBetween = v.day-prevDay _.extend v, daysBetween: daysBetween prevDay = v.day if daysBetween is 0 delete v.daysBetween v #this visit design visitTitleEO: -> visit = @visit design = @design value: visit.title emptytext: "no title" success: (response, newVal) -> Meteor.call "changeStudyDesignVisitTitle", design._id, visit._id, newVal, (error) -> throwError error if error? return #this visit design visitDayEO: -> visit = @visit design = @design value: visit.day emptytext: "no day set" success: (response, newVal) -> Meteor.call "changeStudyDesignVisitDay", design._id, visit._id, newVal, (error) -> throwError error if error? return #this design:StudyDesign visit:StudyDesign.visit questionnaire:Questionnaire questionnaireIconClass: -> questionnaire = @questionnaire found = false if @visit.questionnaireIds _.some @visit.questionnaireIds, (qId)-> found = qId is questionnaire._id found if found return "fa-check-square-o brand-primary" else return "fa-square-o hoverOpaqueExtreme" #this design:StudyDesign visit:StudyDesign.visit physicalIconClass: -> if @visit.recordPhysicalData? and @visit.recordPhysicalData return "fa-check-square-o brand-primary" else return "fa-square-o hoverOpaqueExtreme" Template.editStudyDesigns.events "click #createStudyDesign": (evt) -> Meteor.call "createStudyDesign", @_id, (error, studyDesignId) -> throwError error if error? "click #addVisit": (evt) -> evt.preventDefault() Meteor.call "addStudyDesignVisit", @design._id, (error) -> throwError error if error? "click .listQuestionnaire": (evt) -> evt.preventDefault() questionnaireId = $(evt.target).data("id") qIds = listQuestionnaireIds.get() or [] qIds.push questionnaireId listQuestionnaireIds.set qIds "click .listRecordPhysicalData": (evt) -> evt.preventDefault() listRecordPhysicalData.set !listRecordPhysicalData.get() "click .toggleQuestionnaireAtVisit": (evt) -> evt.preventDefault() questionnaire = @questionnaire found = false if @visit.questionnaireIds _.some @visit.questionnaireIds, (qId)-> found = qId is questionnaire._id found doSchedule = !found Meteor.call "scheduleQuestionnaireAtVisit", @design._id, @visit._id, @questionnaire._id, doSchedule, (error) -> throwError error if error? "click .toggleRecordPhysicalDataAtVisit": (evt) -> evt.preventDefault() Meteor.call "scheduleRecordPhysicalDataAtVisit", @design._id, @visit._id, !@visit.recordPhysicalData, (error) -> throwError error if error? + "click .moveUp": (evt) -> + Meteor.call "moveStudyDesignVisit", @design._id, @visit._id, true, (error) -> + throwError error if error? + + "click .moveDown": (evt) -> + Meteor.call "moveStudyDesignVisit", @design._id, @visit._id, false, (error) -> + throwError error if error? + "click .remove": (evt) -> evt.preventDefault() if confirm "Are you sure?" Meteor.call "removeStudyDesignVisit", @design._id, @visit._id, (error) -> throwError error if error? diff --git a/app/client/views/studies/edit_study_designs.html b/app/client/views/studies/edit_study_designs.html index cfb2922..7ebfe79 100644 --- a/app/client/views/studies/edit_study_designs.html +++ b/app/client/views/studies/edit_study_designs.html @@ -1,102 +1,112 @@ diff --git a/app/lib/collections/studie_designs.coffee b/app/lib/collections/studie_designs.coffee index beb1d56..fa93bad 100644 --- a/app/lib/collections/studie_designs.coffee +++ b/app/lib/collections/studie_designs.coffee @@ -1,206 +1,236 @@ class @StudyDesign constructor: (doc) -> _.extend this, doc @StudyDesigns = new Meteor.Collection("study_designs", transform: (doc) -> new StudyDesign(doc) ) StudyDesigns.before.insert BeforeInsertTimestampHook StudyDesigns.before.update BeforeUpdateTimestampHook schema = 'title': type: String 'studyId': type: String 'creatorId': type: String 'visits': type: [Object] optional: true 'visits._id': type: String 'visits.title': type: String 'visits.index': type: Number #TODO: attach schema #StudyDesigns.attachSchema new SimpleSchema(schema) StudyDesigns.allow update: (userId, doc, fieldNames, modifier) -> #TODO check if allowed notAllowedFields = _.without fieldNames, 'title', 'updatedAt' return false if notAllowedFields.length > 0 true #TODO secure methods Meteor.methods "createStudyDesign": (studyId, title) -> count = StudyDesigns.find( studyId: studyId ).count() _id = StudyDesigns.insert title: "design #{count+1}" studyId: studyId creatorId: Meteor.userId() visits: [ _id: new Meteor.Collection.ObjectID()._str day: 0 index: 0 title: "visit 1" ] _id "removeStudyDesign": (_id) -> #TODO: check if allowed StudyDesigns.remove _id: _id "addStudyDesignVisit": (studyDesignId) -> check studyDesignId, String design = StudyDesigns.findOne _id: studyDesignId throw new Meteor.Error(500, "StudyDesign #{studyDesignId} not found!") unless design? index = design.visits.length title = "visit #{index+1}" visit = _id: new Meteor.Collection.ObjectID()._str title: title index: index StudyDesigns.update _id: studyDesignId , $push: visits: visit "changeStudyDesignVisitTitle": (studyDesignId, visitId, title) -> check studyDesignId, String check visitId, String check title, String n = StudyDesigns.update _id: studyDesignId 'visits._id': visitId , $set: 'visits.$.title': title throw new Meteor.Error(500, "changeStudyVisitTitle: no StudyDesign.visit to update found") unless n > 0 "changeStudyDesignVisitDay": (studyDesignId, visitId, day) -> check studyDesignId, String check visitId, String day = parseInt(day) check day, Number n = StudyDesigns.update _id: studyDesignId 'visits._id': visitId , $set: 'visits.$.day': day throw new Meteor.Error(500, "changeStudyVisitTitle: no StudyDesign.visit to update found") unless n > 0 "scheduleQuestionnaireAtVisit": (studyDesignId, visitId, questionnaireId, doSchedule) -> check studyDesignId, String check visitId, String check questionnaireId, String find = _id: studyDesignId 'visits._id': visitId if doSchedule n = StudyDesigns.update find, $push: 'visits.$.questionnaireIds': questionnaireId else n = StudyDesigns.update find, $pull: 'visits.$.questionnaireIds': questionnaireId throw new Meteor.Error(500, "scheduleQuestionnaireAtVisit: no StudyDesign with that visit found") unless n > 0 updateQuestionnaireIds(studyDesignId) return "scheduleRecordPhysicalDataAtVisit": (studyDesignId, visitId, doSchedule) -> check visitId, String check studyDesignId, String n = StudyDesigns.update _id: studyDesignId 'visits._id': visitId , $set: 'visits.$.recordPhysicalData': doSchedule throw new Meteor.Error(500, "scheduleRecordPhysicalDataAtVisit: no StudyDesign with that visit found") unless n > 0 updateRecordPhysicalData(studyDesignId) return + "moveStudyDesignVisit": (studyDesignId, visitId, up) -> + check visitId, String + check studyDesignId, String + + design = StudyDesigns.findOne + _id: studyDesignId + throw new Meteor.Error(500, "removeStudyDesignVisit: studyDesign not found") unless design? + + visit = _.find design.visits, (v) -> + v._id is visitId + throw new Meteor.Error(500, "removeStudyDesignVisit: visit not found") unless visit? + + move = -1 + move = 1 if !up + return if visit.index is 0 and move is -1 + return if visit.index+1 >= design.visits.length and move is 1 + StudyDesigns.update + _id: studyDesignId + 'visits.index': visit.index+move + , + $inc: + 'visits.$.index': -move + StudyDesigns.update + _id: studyDesignId + 'visits._id': visitId + , + $inc: + 'visits.$.index': move + + "removeStudyDesignVisit": (studyDesignId, visitId) -> check visitId, String check studyDesignId, String design = StudyDesigns.findOne _id: studyDesignId throw new Meteor.Error(500, "removeStudyDesignVisit: studyDesign not found") unless design? visit = _.find design.visits, (v) -> v._id is visitId throw new Meteor.Error(500, "removeStudyDesignVisit: visit not found") unless visit? StudyDesigns.update _id: studyDesignId , $pull: {visits: {_id: visitId}} #TODO normalize visits into it's own collection #to avoid stuff like this index = visit.index+1 loop n = StudyDesigns.update _id: studyDesignId 'visits.index': index , $inc: {'visits.$.index': -1} index += 1 break if n is 0 updateQuestionnaireIds(studyDesignId) updateRecordPhysicalData(studyDesignId) return updateQuestionnaireIds = (studyDesignId) -> design = StudyDesigns.findOne studyDesignId throw new Meteor.Error(500, "updateQuestionnaireIds: studyDesign not found") unless design? questionnaireIds = [] design.visits.forEach (visit) -> if visit.questionnaireIds? and visit.questionnaireIds.length > 0 questionnaireIds = _.union questionnaireIds, visit.questionnaireIds StudyDesigns.update _id: studyDesignId , $set: questionnaireIds: questionnaireIds updateRecordPhysicalData = (studyDesignId) -> design = StudyDesigns.findOne studyDesignId throw new Meteor.Error(500, "updateRecordPhysicalData: studyDesign not found") unless design? recordPhysicalData = false _.some design.visits, (visit) -> if visit.recordPhysicalData? recordPhysicalData = visit.recordPhysicalData recordPhysicalData StudyDesigns.update _id: studyDesignId , $set: recordPhysicalData: recordPhysicalData