polish the poll form
This commit is contained in:
parent
e2dc0d85fc
commit
1a989d0661
@ -264,6 +264,15 @@ option {
|
|||||||
background-color: var(--bg, $fallback--bg);
|
background-color: var(--bg, $fallback--bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hide-number-spinner {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
&[type=number]::-webkit-inner-spin-button,
|
||||||
|
&[type=number]::-webkit-outer-spin-button {
|
||||||
|
opacity: 0;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i[class*=icon-] {
|
i[class*=icon-] {
|
||||||
color: $fallback--icon;
|
color: $fallback--icon;
|
||||||
color: var(--icon, $fallback--icon)
|
color: var(--icon, $fallback--icon)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="poll-form" v-if="visible">
|
<div class="poll-form" v-if="visible">
|
||||||
<hr>
|
|
||||||
<div class="poll-option" v-for="(option, index) in options" :key="index">
|
<div class="poll-option" v-for="(option, index) in options" :key="index">
|
||||||
<div class="input-container">
|
<div class="input-container">
|
||||||
<input
|
<input
|
||||||
@ -8,23 +7,28 @@
|
|||||||
type="text"
|
type="text"
|
||||||
:placeholder="$t('polls.option')"
|
:placeholder="$t('polls.option')"
|
||||||
:maxlength="maxLength"
|
:maxlength="maxLength"
|
||||||
|
:id="`poll-${index}`"
|
||||||
v-model="options[index]"
|
v-model="options[index]"
|
||||||
@change="updatePollToParent"
|
@change="updatePollToParent"
|
||||||
|
@keydown.enter.stop.prevent="nextOption(index)"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon-container" v-if="options.length > 2">
|
<div class="icon-container" v-if="options.length > 2">
|
||||||
<i class="icon-cancel" @click="deleteOption(index)"></i>
|
<i class="icon-cancel" @click="deleteOption(index)"></i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<a
|
||||||
class="btn btn-default add-option"
|
v-if="options.length < maxOptions"
|
||||||
type="button"
|
class="add-option"
|
||||||
@click="addOption"
|
@click="addOption"
|
||||||
>{{ $t("polls.add_option") }}</button>
|
>
|
||||||
|
<i class="icon-plus" />
|
||||||
|
{{ $t("polls.add_option") }}
|
||||||
|
</a>
|
||||||
<div class="poll-type-expiry">
|
<div class="poll-type-expiry">
|
||||||
<div class="poll-type">
|
<div class="poll-type">
|
||||||
<label for="poll-type-selector" class="select">
|
<label for="poll-type-selector" class="select">
|
||||||
<select id="poll-type-selector" v-model="pollType" @change="updatePollToParent">
|
<select class="select" v-model="pollType" @change="updatePollToParent">
|
||||||
<option value="single">{{$t('polls.single_choice')}}</option>
|
<option value="single">{{$t('polls.single_choice')}}</option>
|
||||||
<option value="multiple">{{$t('polls.multiple_choices')}}</option>
|
<option value="multiple">{{$t('polls.multiple_choices')}}</option>
|
||||||
</select>
|
</select>
|
||||||
@ -32,10 +36,18 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="poll-expiry">
|
<div class="poll-expiry">
|
||||||
<label for="poll-expiry-selector" class="select">
|
<input
|
||||||
<select id="poll-expiry-selector" v-model="pollExpiry" @change="updatePollToParent">
|
type="number"
|
||||||
<option v-for="(value, key) in expiryOptions" :value="key" v-bind:key="key">
|
class="expiry-amount hide-number-spinner"
|
||||||
{{ value }}
|
min="1"
|
||||||
|
max="120"
|
||||||
|
v-model="expiryAmount"
|
||||||
|
@change="expiryAmountChange"
|
||||||
|
>
|
||||||
|
<label class="expiry-unit select">
|
||||||
|
<select v-model="expiryUnit" @change="updatePollToParent">
|
||||||
|
<option v-for="unit in expiryUnits" :value="unit">
|
||||||
|
{{ $t(`time.${unit}_short`, ['']) }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<i class="icon-down-open"/>
|
<i class="icon-down-open"/>
|
||||||
@ -46,15 +58,17 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { pickBy } from 'lodash'
|
import * as DateUtils from 'src/services/date_utils/date_utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'PollForm',
|
name: 'PollForm',
|
||||||
props: ['visible'],
|
props: ['visible'],
|
||||||
data: () => ({
|
data: () => ({
|
||||||
pollType: 'single',
|
pollType: 'single',
|
||||||
pollExpiry: '86400',
|
options: ['', ''],
|
||||||
options: ['', '']
|
expiryAmount: 1,
|
||||||
|
expiryUnit: 'minutes',
|
||||||
|
expiryUnits: ['minutes', 'hours', 'days']
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
pollLimits () {
|
pollLimits () {
|
||||||
@ -65,39 +79,57 @@ export default {
|
|||||||
},
|
},
|
||||||
maxLength () {
|
maxLength () {
|
||||||
return this.pollLimits.max_option_chars
|
return this.pollLimits.max_option_chars
|
||||||
},
|
|
||||||
expiryOptions () {
|
|
||||||
const minExpiration = this.pollLimits.min_expiration
|
|
||||||
const maxExpiration = this.pollLimits.max_expiration
|
|
||||||
const expiryOptions = this.$t('polls.expiry_options')
|
|
||||||
|
|
||||||
return pickBy(expiryOptions, (_value, key) => {
|
|
||||||
if (key === 'custom') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
const parsedKey = parseInt(key)
|
|
||||||
|
|
||||||
return (parsedKey >= minExpiration && parsedKey <= maxExpiration)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
clear () {
|
||||||
|
this.pollType = 'single'
|
||||||
|
this.options = ['', '']
|
||||||
|
this.expiryAmount = 1
|
||||||
|
this.expiryUnit = 'minutes'
|
||||||
|
},
|
||||||
|
nextOption (index) {
|
||||||
|
const element = this.$el.querySelector(`#poll-${index+1}`)
|
||||||
|
if (element) {
|
||||||
|
element.focus()
|
||||||
|
} else {
|
||||||
|
// Try adding an option and try focusing on it
|
||||||
|
const addedOption = this.addOption()
|
||||||
|
if (addedOption) {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
this.nextOption(index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
addOption () {
|
addOption () {
|
||||||
if (this.options.length < this.maxOptions) {
|
if (this.options.length < this.maxOptions) {
|
||||||
this.options.push('')
|
this.options.push('')
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
},
|
},
|
||||||
deleteOption (index, event) {
|
deleteOption (index, event) {
|
||||||
if (this.options.length > 2) {
|
if (this.options.length > 2) {
|
||||||
this.options.splice(index, 1)
|
this.options.splice(index, 1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
expiryAmountChange () {
|
||||||
|
this.expiryAmount = Math.max(1, this.expiryAmount)
|
||||||
|
this.expiryAmount = Math.min(120, this.expiryAmount)
|
||||||
|
this.updatePollToParent()
|
||||||
|
},
|
||||||
updatePollToParent () {
|
updatePollToParent () {
|
||||||
|
const unitMultiplier = this.expiryUnit === 'minutes' ? 60
|
||||||
|
: this.expiryUnit === 'hours' ? 60 * 60
|
||||||
|
: 60 * 60 * 24
|
||||||
|
|
||||||
|
const expiresIn = this.expiryAmount * unitMultiplier
|
||||||
|
|
||||||
this.$emit('update-poll', {
|
this.$emit('update-poll', {
|
||||||
options: this.options,
|
options: this.options,
|
||||||
expiresIn: this.pollExpiry,
|
multiple: this.pollType === 'multiple',
|
||||||
multiple: this.pollType === 'multiple'
|
expiresIn
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,40 +137,70 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
@import '../../../_variables.scss';
|
||||||
|
|
||||||
.poll-form {
|
.poll-form {
|
||||||
padding: 0 0.5em 0.6em;
|
display: flex;
|
||||||
hr {
|
flex-direction: column;
|
||||||
margin: 0 0 0.8em;
|
padding: 0 0.5em 0.5em;
|
||||||
border: solid 1px #1c2735;
|
|
||||||
}
|
|
||||||
.add-option {
|
.add-option {
|
||||||
margin: 0.8em 0 0.8em;
|
align-self: flex-start;
|
||||||
width: 94%;
|
padding-top: 0.25em;
|
||||||
|
cursor: pointer;
|
||||||
|
color: $fallback--faint;
|
||||||
|
color: var(--faint, $fallback--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-option {
|
.poll-option {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
margin-bottom: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-container {
|
.input-container {
|
||||||
width: 94%;
|
width: 100%;
|
||||||
input {
|
input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-container {
|
.icon-container {
|
||||||
width: 5%;
|
// Move the icon over the input box
|
||||||
|
width: 2em;
|
||||||
|
margin-left: -2em;
|
||||||
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-type-expiry {
|
.poll-type-expiry {
|
||||||
|
margin-top: 0.5em;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
margin: 0 0 0.6em;
|
|
||||||
}
|
|
||||||
.poll-expiry-custom {
|
|
||||||
display: none;
|
|
||||||
input {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.poll-type {
|
||||||
|
margin-right: 0.75em;
|
||||||
|
flex: 1 1 60%;
|
||||||
|
.select {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.poll-expiry {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.expiry-amount {
|
||||||
|
width: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expiry-unit {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -82,7 +82,7 @@ const PostStatusForm = {
|
|||||||
contentType
|
contentType
|
||||||
},
|
},
|
||||||
caret: 0,
|
caret: 0,
|
||||||
pollFormVisible: false
|
pollFormVisible: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -259,6 +259,8 @@ const PostStatusForm = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const poll = this.pollFormVisible ? this.poll : {}
|
||||||
|
|
||||||
this.posting = true
|
this.posting = true
|
||||||
statusPoster.postStatus({
|
statusPoster.postStatus({
|
||||||
status: newStatus.status,
|
status: newStatus.status,
|
||||||
@ -266,10 +268,10 @@ const PostStatusForm = {
|
|||||||
visibility: newStatus.visibility,
|
visibility: newStatus.visibility,
|
||||||
sensitive: newStatus.nsfw,
|
sensitive: newStatus.nsfw,
|
||||||
media: newStatus.files,
|
media: newStatus.files,
|
||||||
poll: newStatus.poll,
|
|
||||||
store: this.$store,
|
store: this.$store,
|
||||||
inReplyToStatusId: this.replyTo,
|
inReplyToStatusId: this.replyTo,
|
||||||
contentType: newStatus.contentType
|
contentType: newStatus.contentType,
|
||||||
|
poll
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
if (!data.error) {
|
if (!data.error) {
|
||||||
this.newStatus = {
|
this.newStatus = {
|
||||||
@ -282,6 +284,7 @@ const PostStatusForm = {
|
|||||||
}
|
}
|
||||||
this.pollFormVisible = false
|
this.pollFormVisible = false
|
||||||
this.$refs.mediaUpload.clearFile()
|
this.$refs.mediaUpload.clearFile()
|
||||||
|
this.$refs.pollForm.clear()
|
||||||
this.$emit('posted')
|
this.$emit('posted')
|
||||||
let el = this.$el.querySelector('textarea')
|
let el = this.$el.querySelector('textarea')
|
||||||
el.style.height = 'auto'
|
el.style.height = 'auto'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-status-form">
|
<div class="post-status-form">
|
||||||
<form @submit.prevent="postStatus(newStatus)">
|
<form @submit.prevent="postStatus(newStatus)" autocomplete="off">
|
||||||
<div class="form-group" >
|
<div class="form-group" >
|
||||||
<i18n
|
<i18n
|
||||||
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'"
|
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'"
|
||||||
@ -92,7 +92,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<poll-form v-if="pollsAvailable" :visible="pollFormVisible" @update-poll="setPoll" />
|
<poll-form
|
||||||
|
ref="pollForm"
|
||||||
|
v-if="pollsAvailable"
|
||||||
|
:visible="pollFormVisible"
|
||||||
|
@update-poll="setPoll"
|
||||||
|
/>
|
||||||
<div class='form-bottom'>
|
<div class='form-bottom'>
|
||||||
<media-upload ref="mediaUpload" @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="uploadFailed" :drop-files="dropFiles"></media-upload>
|
<media-upload ref="mediaUpload" @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="uploadFailed" :drop-files="dropFiles"></media-upload>
|
||||||
<div v-if="pollsAvailable" class="poll-icon">
|
<div v-if="pollsAvailable" class="poll-icon">
|
||||||
@ -100,7 +105,7 @@
|
|||||||
class="btn btn-default"
|
class="btn btn-default"
|
||||||
:title="$t('tool_tip.poll')"
|
:title="$t('tool_tip.poll')"
|
||||||
@click="togglePollForm">
|
@click="togglePollForm">
|
||||||
<i class="icon-chart-bar"></i>
|
<i class="icon-chart-bar" :class="pollFormVisible && 'selected'" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="isOverLengthLimit" class="error">{{ charactersLeft }}</p>
|
<p v-if="isOverLengthLimit" class="error">{{ charactersLeft }}</p>
|
||||||
@ -300,6 +305,11 @@
|
|||||||
.poll-icon {
|
.poll-icon {
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
color: $fallback--lightText;
|
||||||
|
color: var(--lightText, $fallback--lightText);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-chart-bar {
|
.icon-chart-bar {
|
||||||
|
@ -84,17 +84,8 @@
|
|||||||
"option": "Option",
|
"option": "Option",
|
||||||
"votes": "votes",
|
"votes": "votes",
|
||||||
"vote": "Vote",
|
"vote": "Vote",
|
||||||
"single_choice": "Allow one choice",
|
"single_choice": "Single choice",
|
||||||
"multiple_choices": "Allow multiple choices",
|
"multiple_choices": "Multiple choices"
|
||||||
"expiry_options": {
|
|
||||||
"300": "5 minutes",
|
|
||||||
"1800": "30 minutes",
|
|
||||||
"3600": "1 hour",
|
|
||||||
"21600": "6 hours",
|
|
||||||
"86400": "1 day",
|
|
||||||
"259200": "3 days",
|
|
||||||
"604800": "7 days"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"interactions": {
|
"interactions": {
|
||||||
"favs_repeats": "Repeats and Favorites",
|
"favs_repeats": "Repeats and Favorites",
|
||||||
|
@ -12,7 +12,6 @@ import chatModule from './modules/chat.js'
|
|||||||
import oauthModule from './modules/oauth.js'
|
import oauthModule from './modules/oauth.js'
|
||||||
import mediaViewerModule from './modules/media_viewer.js'
|
import mediaViewerModule from './modules/media_viewer.js'
|
||||||
import oauthTokensModule from './modules/oauth_tokens.js'
|
import oauthTokensModule from './modules/oauth_tokens.js'
|
||||||
import pollModule from './modules/poll.js'
|
|
||||||
import reportsModule from './modules/reports.js'
|
import reportsModule from './modules/reports.js'
|
||||||
|
|
||||||
import VueI18n from 'vue-i18n'
|
import VueI18n from 'vue-i18n'
|
||||||
@ -69,7 +68,6 @@ const persistedStateOptions = {
|
|||||||
oauth: oauthModule,
|
oauth: oauthModule,
|
||||||
mediaViewer: mediaViewerModule,
|
mediaViewer: mediaViewerModule,
|
||||||
oauthTokens: oauthTokensModule,
|
oauthTokens: oauthTokensModule,
|
||||||
poll: pollModule,
|
|
||||||
reports: reportsModule
|
reports: reportsModule
|
||||||
},
|
},
|
||||||
plugins: [persistedState, pushNotifications],
|
plugins: [persistedState, pushNotifications],
|
||||||
|
@ -60,7 +60,7 @@ const defaultState = {
|
|||||||
max_options: 4,
|
max_options: 4,
|
||||||
max_option_chars: 255,
|
max_option_chars: 255,
|
||||||
min_expiration: 60,
|
min_expiration: 60,
|
||||||
max_expiration: 300
|
max_expiration: 600
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
const poll = {
|
|
||||||
state: {
|
|
||||||
options: ['', ''],
|
|
||||||
multiple: false,
|
|
||||||
expiresIn: '86400'
|
|
||||||
},
|
|
||||||
mutations: {
|
|
||||||
ADD_OPTION (state, { option }) {
|
|
||||||
state.options.push(option)
|
|
||||||
},
|
|
||||||
UPDATE_OPTION (state, { index, option }) {
|
|
||||||
state.options[index] = option
|
|
||||||
},
|
|
||||||
DELETE_OPTION (state, { index }) {
|
|
||||||
state.options.splice(index, 1)
|
|
||||||
},
|
|
||||||
SWAP_OPTIONS (state, { options }) {
|
|
||||||
state.options = options
|
|
||||||
},
|
|
||||||
SET_MULTIPLE (state, { multiple }) {
|
|
||||||
state.multiple = multiple
|
|
||||||
},
|
|
||||||
SET_EXPIRES_IN (state, { expiresIn }) {
|
|
||||||
state.expiresIn = expiresIn
|
|
||||||
}
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
addPollOption (store, { option }) {
|
|
||||||
store.commit('ADD_OPTION', { option })
|
|
||||||
},
|
|
||||||
updatePollOption (store, { index, option }) {
|
|
||||||
store.commit('UPDATE_OPTION', { index, option })
|
|
||||||
},
|
|
||||||
deletePollOption (store, { index }) {
|
|
||||||
store.commit('DELETE_OPTION', { index })
|
|
||||||
},
|
|
||||||
swapPollOptions (store, { options }) {
|
|
||||||
store.commit('SWAP_OPTIONS', { options })
|
|
||||||
},
|
|
||||||
setMultiple (store, { multiple }) {
|
|
||||||
store.commit('SET_MULTIPLE', { multiple })
|
|
||||||
},
|
|
||||||
setExpiresIn (store, { expiresIn }) {
|
|
||||||
store.commit('SET_EXPIRES_IN', { expiresIn })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default poll
|
|
Loading…
x
Reference in New Issue
Block a user