Version 1.0.3

This commit is contained in:
affan98 2019-05-14 03:03:59 -04:00
commit 1fce2a39fb
30 changed files with 174 additions and 1006 deletions

View file

@ -23,6 +23,9 @@
<template>
<div class="controls">
<div class="breadcrumb">
<button class="button btn primary" @click="helpPage">
{{ "Help" }}
</button>
<div class="crumb svg crumbhome">
<router-link :to="{ name: 'list'}" class="icon-home">
Home
@ -52,6 +55,11 @@ export default {
return {
imagePath: OC.imagePath('core', 'places/home.svg')
}
},
methods: {
helpPage() {
window.open('https://github.com/affan98/forms/blob/master/Forms_Support.md')
}
}
}
</script>

View file

@ -71,7 +71,7 @@
<div>
<img class="icontwo">
</div>
<div v-if="votedBycurrentUser" class="symbol icon-voted" />
<div class="symbol icon-voted" />
<a :href="voteUrl" class="wrapper group-1-1">
<div class="name">
{{ form.event.title }}
@ -173,19 +173,11 @@ export default {
return t('forms', 'never')
}
},
participants() {
return this.form.votes.map(item => item.userId)
.filter((value, index, self) => self.indexOf(value) === index)
},
countvotes() {
return this.participants.length
},
countShares() {
return this.form.shares.length
},
votedBycurrentUser() {
return this.participants.indexOf(OC.getCurrentUser().uid) > -1
},
voteUrl() {
return OC.generateUrl('apps/forms/form/') + this.form.event.hash
}

View file

@ -23,7 +23,7 @@
<li>
<div>{{ question.text }}</div>
<div>
<input v-show="question.type != 'text'" style="height:30px;" v-model="newQuizAnswer"
<input v-show="(question.type != 'text') && (question.type != 'comment')" style="height:30px;" v-model="newQuizAnswer"
:placeholder=" t('forms', 'Add Answer')"
@keyup.enter="emitNewAnswer(question)"
>

View file

@ -28,7 +28,6 @@ import Router from 'vue-router'
// Dynamic loading
const Create = () => import('./views/Create')
const List = () => import('./views/List')
const Vote = () => import('./views/Vote')
const Results = () => import('./views/Results')
Vue.use(Router)
@ -76,14 +75,6 @@ export default new Router({
},
props: false,
name: 'create'
},
{
path: '/:index(index.php/)?apps/forms/form/:hash',
components: {
default: Vote
},
props: false,
name: 'create'
}
]
})

View file

@ -129,10 +129,6 @@
<input v-show="form.event.isAnonymous" id="trueAnonymous" v-model="form.event.fullAnonymous"
:disabled="protect" type="checkbox" class="checkbox"
>
<label v-show="form.event.isAnonymous" class="title" for="trueAnonymous">
{{ t('forms', 'Hide user names for admin') }}
</label>
<input id="expiration" v-model="form.event.expiration" :disabled="protect"
type="checkbox" class="checkbox"
>
@ -255,7 +251,8 @@ export default {
options: [
{ text: 'Radio Buttons', value: 'radiogroup' },
{ text: 'Checkboxes', value: 'checkbox' },
{ text: 'Write In', value: 'text' },
{ text: 'Short Response', value: 'text' },
{ text: 'Long Response', value: 'comment' },
{ text: 'Drop Down', value: 'dropdown' }
]
}
@ -285,7 +282,7 @@ export default {
} else if (this.form.mode === 'edit') {
return t('forms', 'Update form')
} else {
return t('forms', 'Create new form')
return t('forms', 'Done')
}
},
@ -412,7 +409,7 @@ export default {
} else if (!this.uniqueName) {
OC.Notification.showTemporary(t('forms', 'Cannot have the same question!'))
} else {
if (this.newQuizQuestion !== null & this.newQuizQuestion !== '') {
if (this.newQuizQuestion !== null & this.newQuizQuestion !== '' & (/\S/.test(this.newQuizQuestion))) {
this.form.options.formQuizQuestions.push({
id: this.nextQuizQuestionId++,
text: this.newQuizQuestion,
@ -443,7 +440,7 @@ export default {
if (!this.uniqueAnsName) {
OC.Notification.showTemporary(t('forms', 'Two answers cannot be the same!'))
} else {
if (item.newQuizAnswer !== null & item.newQuizAnswer !== '') {
if (item.newQuizAnswer !== null & item.newQuizAnswer !== '' & (/\S/.test(item.newQuizAnswer))) {
item.formQuizAnswers.push({
id: item.nextQuizAnswerId,
text: item.newQuizAnswer
@ -461,7 +458,7 @@ export default {
allHaveAns() {
this.haveAns = true
this.form.options.formQuizQuestions.forEach(q => {
if (q.type !== 'text' && q.answers.length === 0) {
if (q.type !== 'text' && q.type !== 'comment' && q.answers.length === 0) {
this.haveAns = false
}
})
@ -472,13 +469,15 @@ export default {
if (mode !== '') {
this.form.mode = mode
}
if (this.form.event.title.length === 0) {
if (this.form.event.title.length === 0 | !(/\S/.test(this.form.event.title))) {
this.titleEmpty = true
OC.Notification.showTemporary(t('forms', 'Title must not be empty!'))
} else if (this.form.options.formQuizQuestions.length === 0) {
OC.Notification.showTemporary(t('forms', 'Must have at least one question!'))
} else if (!this.haveAns) {
OC.Notification.showTemporary(t('forms', 'All questions need answers!'))
} else if (this.form.event.expiration & this.form.event.expirationDate === '') {
OC.Notification.showTemporary(t('forms', 'Need to pick an expiration date!'))
} else {
this.writingForm = true
this.titleEmpty = false

View file

@ -31,7 +31,6 @@
</span>
</router-link>
</controls>
<div v-if="noForms" class="">
<div class="icon-forms" />
<h2> {{ t('No existing forms.') }} </h2>
@ -39,7 +38,6 @@
<span>{{ t('forms', 'Click here to add a form') }}</span>
</router-link>
</div>
<transition-group
v-if="!noForms"
name="list"
@ -102,7 +100,9 @@ export default {
this.loading = false
})
},
helpPage() {
window.open('https://github.com/affan98/forms/blob/master/Forms_Support.md')
},
viewFormResults(index, event, name) {
this.$router.push({
name: name,

View file

@ -23,31 +23,39 @@
-->
<template>
<div id="app-content">
<div>
<div>
<button class="button btn primary" @click="download">
<span>{{ "Export to CSV" }}</span>
</button>
</div>
<transition-group
name="list"
tag="div"
class="table"
>
<resultItem
key="0"
:header="true"
/>
<li
is="resultItem"
v-for="(vote, index) in votes"
:key="vote.id"
:vote="vote"
@viewResults="viewFormResults(index, form.event, 'results')"
/>
</transition-group>
<loading-overlay v-if="loading" />
<modal-dialog />
<h1>
{{ "Statistics" }}
</h1>
<div v-for="sum in stats" :key="sum">
{{ sum }}
</div>
<div id="app-content">
<transition-group
name="list"
tag="div"
class="table"
>
<resultItem
key="0"
:header="true"
/>
<li
is="resultItem"
v-for="(vote, index) in votes"
:key="vote.id"
:vote="vote"
@viewResults="viewFormResults(index, form.event, 'results')"
/>
</transition-group>
<loading-overlay v-if="loading" />
<modal-dialog />
</div>
</div>
</template>
@ -68,6 +76,7 @@ export default {
return {
loading: true,
votes: []
}
},
@ -81,7 +90,12 @@ export default {
this.loading = true
this.$http.get(OC.generateUrl('apps/forms/get/votes/' + this.$route.params.hash))
.then((response) => {
this.votes = response.data
if (response.data == null) {
this.votes = null
OC.Notification.showTemporary('Access Denied')
} else {
this.votes = response.data
}
this.loading = false
}, (error) => {
/* eslint-disable-next-line no-console */
@ -98,16 +112,57 @@ export default {
})
},
download() {
this.json2csvParser = ['userId', 'voteOptionId', 'voteOptionText', 'voteAnswer']
var element = document.createElement('a')
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(json2csvParser.parse(this.votes)))
element.setAttribute('download', 'NextCloud Forms CSV' + '.csv')
element.style.display = 'none'
document.body.appendChild(element)
this.loading = true
this.$http.get(OC.generateUrl('apps/forms/get/event/' + this.$route.params.hash))
.then((response) => {
this.json2csvParser = ['userId', 'voteOptionId', 'voteOptionText', 'voteAnswer']
var element = document.createElement('a')
element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(json2csvParser.parse(this.votes)))
element.setAttribute('download', response.data.title + '.csv')
element.click()
document.body.removeChild(element)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
this.loading = false
}, (error) => {
/* eslint-disable-next-line no-console */
console.log(error.response)
this.loading = false
})
}
},
computed: {
stats() {
if (this.votes != null) {
var uniqueAns = []
var uniqueQs = []
var ansToQ = new Map()
for (let i = 0; i < this.votes.length; i++) {
if (this.votes[i].voteOptionType === 'radiogroup' || this.votes[i].voteOptionType === 'dropdown') {
if (uniqueAns.includes(this.votes[i].voteAnswer) === false) {
uniqueAns.push(this.votes[i].voteAnswer)
ansToQ.set(this.votes[i].voteAnswer, this.votes[i].voteOptionId)
}
if (uniqueQs.includes(this.votes[i].voteOptionId) === false) {
uniqueQs.push(this.votes[i].voteOptionId)
}
}
}
var sums = []
for (let i = 0; i < uniqueAns.length; i++) {
sums[i] = 0
}
for (let i = 0; i < this.votes.length; i++) {
sums[uniqueAns.indexOf(this.votes[i].voteAnswer)]++
}
for (let i = 0; i < sums.length; i++) {
sums[i] = 'Question ' + ansToQ.get(uniqueAns[i]) + ': ' + (sums[i] / ((this.votes.length / uniqueQs.length)) * 100).toFixed(2) + '%' + ' of respondents voted for answer choice: ' + uniqueAns[i]
}
}
return sums.sort()
}
}
}

View file

@ -1,176 +0,0 @@
<!--
- @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de>
-
- @author Natalie Gilbert
- @author Nick Gallo
- @author Affan Hussain
-
- @license GNU AGPL version 3 or any later version
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->
<template>
<div id="app-votes">
<survey :survey="survey"></survey>
</div>
</template>
<script>
import * as SurveyVue from 'survey-vue'
import * as widgets from 'surveyjs-widgets'
// import 'bootstrap/dist/css/bootstrap.css'
var Survey = SurveyVue.Survey
Survey.cssType = 'bootstrap'
// import "inputmask/dist/inputmask/phone-codes/phone.js"
widgets.icheck(SurveyVue)
widgets.select2(SurveyVue)
widgets.inputmask(SurveyVue)
widgets.jquerybarrating(SurveyVue)
widgets.jqueryuidatepicker(SurveyVue)
widgets.nouislider(SurveyVue)
widgets.select2tagbox(SurveyVue)
widgets.signaturepad(SurveyVue)
widgets.sortablejs(SurveyVue)
widgets.ckeditor(SurveyVue)
widgets.autocomplete(SurveyVue)
widgets.bootstrapslider(SurveyVue)
export default {
name: 'AppVote',
components: {
Survey
},
data() {
var json = {
title: '',
questions: []
}
var model = new SurveyVue.Model(json)
return {
loadingForm: false,
writingForm: false,
form: [],
myTitle: '',
quests: [],
survey: model,
ans: []
}
},
created() {
this.indexPage = OC.generateUrl('apps/forms/')
this.loadForm(this.$route.params.hash)
},
methods: {
loadForm(hash) {
this.loadingForm = true
this.$http.get(OC.generateUrl('apps/forms/get/form/' + hash))
.then((response) => {
this.form = response.data
this.myTitle = response.data.event.title
this.quests = response.data.options.formQuizQuestions
this.loadingForm = false
this.setSurvey()
}, (error) => {
/* eslint-disable-next-line no-console */
console.log(error.response)
this.form.event.hash = ''
this.loadingForm = false
})
},
setSurvey() {
this.quests.forEach(q => {
q.answers.forEach(a => {
this.ans.push(a.text)
})
this.survey.pages[0].addNewQuestion(q.type, q.text).choices = this.ans
this.ans = []
this.survey.pages[0].questions.forEach(i => {
i.isRequired = true
})
})
this.survey
.onUpdateQuestionCssClasses
.add(function(survey, options) {
var classes = options.cssClasses
classes.root = 'sq-root'
classes.title = 'sq-title'
classes.item = 'sq-item'
classes.label = 'sq-label'
if (options.question.isRequired) {
classes.title = 'sq-title sq-title-required'
classes.root = 'sq-root sq-root-required'
}
})
this.survey
.onComplete
.add(function(result) {
this.writingForm = true
this.form.answers = result.data
this.form.userId = OC.getCurrentUser().uid
this.form.questions = this.quests
this.$http.post(OC.generateUrl('apps/forms/insert/vote'), this.form)
.then((response) => {
this.writingForm = false
}, (error) => {
/* eslint-disable-next-line no-console */
console.log(error.response)
this.writingForm = false
})
}.bind(this))
}
}
}
</script>
<style lang="scss">
.app-forms {
margin: auto;
width: 50%;
margin-top: 20px;
}
.sv_qstn .sq-root {
border: 1px solid gray;
border-left: 4px solid #18a689;
border-radius: 5px;
padding: 20px;
margin-bottom: 30px;
font-size: 18px;
}
.sq-title {
font-size: 22px;
margin-left: 20px;
}
.sq-title-required {
color: black;
}
.sq-label {
margin-left: 30px;
}
.sq-item:nth-child(1) {
margin-bottom: 5px;
}
</style>