www/project/icla/views/pages/vote.js.rb (239 lines of code) (raw):

class Vote < Vue def initialize @disabled = true @alert = nil # initialize form fields @token = Server.data.token @member = Server.data.member @debug = Server.data.debug console.log('vote') console.log('token: ' + @token) console.log('member: ' + @member) @progress = Server.data.progress console.log('progress: ' + @progress.inspect) if @progress @phase = @progress[:phase] else @phase = 'unknown' # flag end console.log('phase: ' + @phase) if not @token @alert = 'Token is required for this page' elsif @phase == 'unknown' @alert = 'Cannot determine phase: could not read token file' elsif @phase == 'error' @alert = @progress[:errorMessage] elsif @phase != 'vote' @alert = 'Wrong phase: ' + @phase + '; should be vote' else @pmc = @progress[:project] console.log('pmc: ' + @pmc) @proposer = @progress[:proposer] @contributor = @progress[:contributor] @iclaname = @contributor[:name] @iclaemail = @contributor[:email] @comments = @progress[:comments] @votes = @progress[:votes] @vote = '' @timestamp = '' @commentBody = '' @subject = @progress[:subject] @showComment = false; end end def render _p %{ This form allows PMC and PPMC members to vote to invite a contributor to become a committer or a PMC/PPMC member. } if @phase == 'vote' _b 'Project: ' + @pmc _p _b 'Contributor: ' + @iclaname + ' (' + @iclaemail + ')' _p _b 'Proposed by: ' + @proposer _p _p 'Subject: ' + @subject _p _div.form_group.vote do _label do _input type: 'radio', name: 'vote', value: '+1', onClick: lambda {@vote = '+1'; @showComment = false; checkValidity()} _span ' +1 approve ' end _p _label do _input type: 'radio', name: 'vote', value: '+0', onClick: lambda {@vote = '+0'; @showComment = false; checkValidity()} _span " +0 don't care " end _p _label do _input type: 'radio', name: 'vote', value: '-0', onClick: lambda {@vote = '-0'; @showComment = false; checkValidity()} _span " -0 don't care " end _p _label do _input type: 'radio', name: 'vote', value: '-1', onClick: lambda {@vote = '-1'; @showComment = true; checkValidity()} _span ' -1 disapprove, because... ' end _p end # # Form fields # if @showComment _div.form_group do _textarea.form_control rows: 4, placeholder: 'reason to disapprove', id: 'commentBody', value: @commentBody, onChange: self.setCommentBody end end _h5 'Voting history' tally = {} # most recent vote details for each member # previous votes @votes.each {|v| tally[v.member] = [v.vote, v.timestamp] _p v.vote + ' From: ' + v.member + ' Date: ' + v.timestamp } _h5 'Summary of voting so far' vote_count = {} tally.each_key { |k| vote_count[tally[k][0]] ||= 0 vote_count[tally[k][0]] += 1 _ k + ' ' + tally[k][0] + ' ' + tally[k][1] _br } _br vote_count.each_key {|k| _ k + ': ' + vote_count[k] _br } started = new Date(@votes[0]['timestamp']) now = new Date() elapsed = (now - started) / (1000 * 60 * 60) _ 'Voting started: ' + started.toISOString() + ' Hours elapsed: ' + elapsed.to_i _p _h5 'Previous discussion' # previous comments @comments.each {|c| _b 'From: ' + c.member + ' Date: ' + c.timestamp _p c.comment } # # Submission buttons # _p do _button.btn.btn_primary 'Submit my vote', disabled: @disabled, onClick: self.submitVote _b ' or ' _button.btn.btn_primary 'Cancel the vote', disabled: false, onClick: self.cancelVote _b ' or ' _button.btn.btn_primary 'Tally the vote', disabled: false, onClick: self.tallyVote end end if @debug _p 'token: ' + @token _p 'comment: ' + @commentBody _p 'vote: ' + @vote end # error messages if @alert _div.alert.alert_danger do _b 'Error: ' _span @alert end end # # Hidden form: preview invite email # _div.modal.fade.invitation_preview! do _div.modal_dialog do _div.modal_content do _div.modal_header do _button.close "\u00d7", type: 'button', data_dismiss: 'modal' _h4 'Preview Invitation Email' end _div.modal_body do # headers _div do _b 'From: ' _span @memberEmail end _div do _b 'To: ' _span "#{@iclaname} <#{@iclaemail}>" end _div do _b 'cc: ' _span @pmcEmail end # draft invitation email _div.form_group do _label :for => 'invitation' _textarea.form_control.invitation! value: @invitation, rows: 12, onChange: self.setInvitation # does not appear to work end end _div.modal_footer do _button.btn.btn_default 'Cancel', data_dismiss: 'modal' _button.btn.btn_primary 'Mock Send', onClick: self.mockSend end end end end end # TODO: finish the code! def setInvitation(event) console.log('setInvitation:' + event) alert('setInvitation: Not yet implemented') end def submitVote(event) console.log('submitVote:' + event) updateVoteFile('submitVote') end def cancelVote(event) console.log('cancelVote:' + event) updateVoteFile('cancelVote', 'cancelled') end def tallyVote(event) console.log('tallyVote:' + event) updateVoteFile('tallyVote', 'tallied') # is this correct? TODO end def updateVoteFile(action, newPhase) data = { action: action, vote: @vote, member: @member, token: @token, expectedPhase: 'vote', newPhase: newPhase, } data['comment']=@commentBody if @vote == '-1' console.log('>update: '+ data.inspect) # debug post 'update', data do |response| console.log('<update: '+ response.inspect) # debug @alert = response.error unless @alert @votes = response['contents']['votes'] @comments = response['contents']['comments'] end end end # when the form is redisplayed, e.g. after displaying/hiding the commentBody def updated() focusComment() end # when the form is initially loaded def mounted() end # # field setters # def setCommentBody(event) @commentBody = event.target.value checkValidity() end def focusComment() f = document.getElementById('commentBody') f.focus() if f end # # validation and processing # # client side field validations def checkValidity() # disabled if no vote or vote -1 without comment @disabled = (@vote == '' or (@vote == '-1' and @commentBody.empty?)) end # pretend to send an invitation def mockSend() # dismiss modal dialog jQuery('#invitation-preview').modal(:hide) # save information for later use (for demo purposes, this is client only) FormData.token = @token FormData.fullname = @iclaname FormData.email = @iclaemail FormData.pmc = @pmc FormData.votelink = @votelink FormData.noticelink = @noticelink # for demo purposes advance to the interview. Note: the below line # updates the URL in a way that breaks the back button. history.replaceState({}, nil, "form?token=#@token") # change the view Main.navigate(Interview) end end