polish the poll form

This commit is contained in:
shpuld 2019-06-09 22:33:25 +03:00
parent e2dc0d85fc
commit 1a989d0661
8 changed files with 144 additions and 120 deletions

View File

@ -264,6 +264,15 @@ option {
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-] {
color: $fallback--icon;
color: var(--icon, $fallback--icon)

View File

@ -1,6 +1,5 @@
<template>
<div class="poll-form" v-if="visible">
<hr>
<div class="poll-option" v-for="(option, index) in options" :key="index">
<div class="input-container">
<input
@ -8,23 +7,28 @@
type="text"
:placeholder="$t('polls.option')"
:maxlength="maxLength"
:id="`poll-${index}`"
v-model="options[index]"
@change="updatePollToParent"
@keydown.enter.stop.prevent="nextOption(index)"
>
</div>
<div class="icon-container" v-if="options.length > 2">
<i class="icon-cancel" @click="deleteOption(index)"></i>
</div>
</div>
<button
class="btn btn-default add-option"
type="button"
<a
v-if="options.length < maxOptions"
class="add-option"
@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">
<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="multiple">{{$t('polls.multiple_choices')}}</option>
</select>
@ -32,10 +36,18 @@
</label>
</div>
<div class="poll-expiry">
<label for="poll-expiry-selector" class="select">
<select id="poll-expiry-selector" v-model="pollExpiry" @change="updatePollToParent">
<option v-for="(value, key) in expiryOptions" :value="key" v-bind:key="key">
{{ value }}
<input
type="number"
class="expiry-amount hide-number-spinner"
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>
</select>
<i class="icon-down-open"/>
@ -46,15 +58,17 @@
</template>
<script>
import { pickBy } from 'lodash'
import * as DateUtils from 'src/services/date_utils/date_utils'
export default {
name: 'PollForm',
props: ['visible'],
data: () => ({
pollType: 'single',
pollExpiry: '86400',
options: ['', '']
options: ['', ''],
expiryAmount: 1,
expiryUnit: 'minutes',
expiryUnits: ['minutes', 'hours', 'days']
}),
computed: {
pollLimits () {
@ -65,39 +79,57 @@ export default {
},
maxLength () {
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: {
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 () {
if (this.options.length < this.maxOptions) {
this.options.push('')
return true
}
return false
},
deleteOption (index, event) {
if (this.options.length > 2) {
this.options.splice(index, 1)
}
},
expiryAmountChange () {
this.expiryAmount = Math.max(1, this.expiryAmount)
this.expiryAmount = Math.min(120, this.expiryAmount)
this.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', {
options: this.options,
expiresIn: this.pollExpiry,
multiple: this.pollType === 'multiple'
multiple: this.pollType === 'multiple',
expiresIn
})
}
}
@ -105,39 +137,69 @@ export default {
</script>
<style lang="scss">
@import '../../../_variables.scss';
.poll-form {
padding: 0 0.5em 0.6em;
hr {
margin: 0 0 0.8em;
border: solid 1px #1c2735;
}
display: flex;
flex-direction: column;
padding: 0 0.5em 0.5em;
.add-option {
margin: 0.8em 0 0.8em;
width: 94%;
align-self: flex-start;
padding-top: 0.25em;
cursor: pointer;
color: $fallback--faint;
color: var(--faint, $fallback--faint);
}
.poll-option {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 0.25em;
}
.input-container {
width: 94%;
width: 100%;
input {
width: 100%;
}
}
.icon-container {
width: 5%;
// Move the icon over the input box
width: 2em;
margin-left: -2em;
z-index: 1;
}
.poll-type-expiry {
margin-top: 0.5em;
display: flex;
justify-content: space-between;
margin: 0 0 0.6em;
width: 100%;
}
.poll-expiry-custom {
display: none;
input {
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;
}
}
}

View File

@ -50,8 +50,8 @@ const PostStatusForm = {
let statusText = preset || ''
const scopeCopy = typeof this.$store.state.config.scopeCopy === 'undefined'
? this.$store.state.instance.scopeCopy
: this.$store.state.config.scopeCopy
? this.$store.state.instance.scopeCopy
: this.$store.state.config.scopeCopy
if (this.replyTo) {
const currentUser = this.$store.state.users.currentUser
@ -59,8 +59,8 @@ const PostStatusForm = {
}
const scope = (this.copyMessageScope && scopeCopy || this.copyMessageScope === 'direct')
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
? this.copyMessageScope
: this.$store.state.users.currentUser.default_scope
const contentType = typeof this.$store.state.config.postContentType === 'undefined'
? this.$store.state.instance.postContentType
@ -82,7 +82,7 @@ const PostStatusForm = {
contentType
},
caret: 0,
pollFormVisible: false
pollFormVisible: true
}
},
computed: {
@ -138,8 +138,8 @@ const PostStatusForm = {
},
showAllScopes () {
const minimalScopesMode = typeof this.$store.state.config.minimalScopesMode === 'undefined'
? this.$store.state.instance.minimalScopesMode
: this.$store.state.config.minimalScopesMode
? this.$store.state.instance.minimalScopesMode
: this.$store.state.config.minimalScopesMode
return !minimalScopesMode
},
emoji () {
@ -259,6 +259,8 @@ const PostStatusForm = {
}
}
const poll = this.pollFormVisible ? this.poll : {}
this.posting = true
statusPoster.postStatus({
status: newStatus.status,
@ -266,10 +268,10 @@ const PostStatusForm = {
visibility: newStatus.visibility,
sensitive: newStatus.nsfw,
media: newStatus.files,
poll: newStatus.poll,
store: this.$store,
inReplyToStatusId: this.replyTo,
contentType: newStatus.contentType
contentType: newStatus.contentType,
poll
}).then((data) => {
if (!data.error) {
this.newStatus = {
@ -282,6 +284,7 @@ const PostStatusForm = {
}
this.pollFormVisible = false
this.$refs.mediaUpload.clearFile()
this.$refs.pollForm.clear()
this.$emit('posted')
let el = this.$el.querySelector('textarea')
el.style.height = 'auto'

View File

@ -1,6 +1,6 @@
<template>
<div class="post-status-form">
<form @submit.prevent="postStatus(newStatus)">
<form @submit.prevent="postStatus(newStatus)" autocomplete="off">
<div class="form-group" >
<i18n
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private'"
@ -92,7 +92,12 @@
</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'>
<media-upload ref="mediaUpload" @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="uploadFailed" :drop-files="dropFiles"></media-upload>
<div v-if="pollsAvailable" class="poll-icon">
@ -100,7 +105,7 @@
class="btn btn-default"
:title="$t('tool_tip.poll')"
@click="togglePollForm">
<i class="icon-chart-bar"></i>
<i class="icon-chart-bar" :class="pollFormVisible && 'selected'" />
</label>
</div>
<p v-if="isOverLengthLimit" class="error">{{ charactersLeft }}</p>
@ -300,6 +305,11 @@
.poll-icon {
font-size: 26px;
flex: 1;
.selected {
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
}
}
.icon-chart-bar {

View File

@ -84,17 +84,8 @@
"option": "Option",
"votes": "votes",
"vote": "Vote",
"single_choice": "Allow one choice",
"multiple_choices": "Allow 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"
}
"single_choice": "Single choice",
"multiple_choices": "Multiple choices"
},
"interactions": {
"favs_repeats": "Repeats and Favorites",

View File

@ -12,7 +12,6 @@ import chatModule from './modules/chat.js'
import oauthModule from './modules/oauth.js'
import mediaViewerModule from './modules/media_viewer.js'
import oauthTokensModule from './modules/oauth_tokens.js'
import pollModule from './modules/poll.js'
import reportsModule from './modules/reports.js'
import VueI18n from 'vue-i18n'
@ -69,7 +68,6 @@ const persistedStateOptions = {
oauth: oauthModule,
mediaViewer: mediaViewerModule,
oauthTokens: oauthTokensModule,
poll: pollModule,
reports: reportsModule
},
plugins: [persistedState, pushNotifications],

View File

@ -60,7 +60,7 @@ const defaultState = {
max_options: 4,
max_option_chars: 255,
min_expiration: 60,
max_expiration: 300
max_expiration: 600
}
}

View File

@ -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