Adding vue-components
This commit is contained in:
Родитель
cfcd1a054f
Коммит
541612d271
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -116,7 +116,9 @@ class ApiController extends Controller {
|
|||
'id' => $user->getUID(),
|
||||
'type' => 'user',
|
||||
'displayName' => $user->getDisplayName(),
|
||||
'avatarURL' => ''
|
||||
'avatarURL' => '',
|
||||
'lastLogin' => $user->getLastLogin(),
|
||||
'cloudId' => $user->getCloudId()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
"axios": "^0.17.1",
|
||||
"lodash": "^4.17.11",
|
||||
"moment": "^2.22.1",
|
||||
"nextcloud-vue": "^0.1.5",
|
||||
"nextcloud-vue": "^0.2.0",
|
||||
"velocity-animate": "^1.5.1",
|
||||
"vue": "^2.5.16",
|
||||
"vue-js-modal": "^1.3.26"
|
||||
|
|
|
@ -83,7 +83,6 @@
|
|||
<div class="header">
|
||||
<div class="pollInformation flex-column">
|
||||
<user-div :description="t('polls', 'Owner')" :user-id="poll.event.owner"></user-div>
|
||||
<cloud-div v-bind:options="poll.event"></cloud-div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -95,7 +94,7 @@
|
|||
|
||||
<div>
|
||||
<div class="flex-wrap align-centered space-between" v-if="protect">
|
||||
<span>{{ t('polls', 'Configuration is locked. Changing options may result in unwanted behaviour,but you can unlock it anyway.') }}</span>
|
||||
<span>{{ t('polls', 'Configuration is locked. Changing options may result in unwanted behaviour, but you can unlock it anyway.') }}</span>
|
||||
<button @click="protect=false" > {{ t('polls', 'Unlock configuration ') }} </button>
|
||||
</div>
|
||||
<div id="configurationsTabView" class="tab configurationsTabView flex-wrap">
|
||||
|
@ -145,8 +144,7 @@
|
|||
:placeholder="t('polls', 'Name of user or group')"
|
||||
:active-shares="poll.shares"
|
||||
v-show="poll.event.access === 'select'"
|
||||
@add-share="addShare"
|
||||
@remove-share="removeShare"/>
|
||||
:shares="poll.shares"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,9 +197,8 @@
|
|||
}
|
||||
},
|
||||
system:[],
|
||||
lang: OC.getLanguage(),
|
||||
locale: OC.getLocale(),
|
||||
localeData: moment.localeData(moment.locale(OC.getLocale())),
|
||||
lang: '',
|
||||
locale: '',
|
||||
placeholder: '',
|
||||
newPollDate: '',
|
||||
newPollTime: '',
|
||||
|
@ -212,35 +209,27 @@
|
|||
sidebar: false,
|
||||
titleEmpty: false,
|
||||
indexPage: '',
|
||||
longDateFormat: moment.localeData().longDateFormat('L'),
|
||||
dateTimeFormat: moment.localeData().longDateFormat('L') + ' ' + moment.localeData().longDateFormat('LT'),
|
||||
expirationDatePicker: {
|
||||
editable: true,
|
||||
minuteStep: 1,
|
||||
type: 'datetime',
|
||||
format: moment.localeData().longDateFormat('L') + ' ' + moment.localeData().longDateFormat('LT'),
|
||||
lang: OC.getLanguage().split("-")[0],
|
||||
placeholder: t('polls', 'Expiration date')
|
||||
},
|
||||
optionDatePicker: {
|
||||
editable: false,
|
||||
minuteStep: 1,
|
||||
type: 'datetime',
|
||||
format: moment.localeData().longDateFormat('L') + ' ' + moment.localeData().longDateFormat('LT'),
|
||||
lang: OC.getLanguage().split("-")[0],
|
||||
placeholder: t('polls', 'Click to add a date'),
|
||||
timePickerOptions: {
|
||||
start: '00:00',
|
||||
step: '00:05',
|
||||
end: '23:55'
|
||||
}
|
||||
}
|
||||
longDateFormat: '',
|
||||
dateTimeFormat: '',
|
||||
}
|
||||
},
|
||||
|
||||
created: function() {
|
||||
this.indexPage = OC.generateUrl('apps/polls/');
|
||||
this.getSystemValues();
|
||||
this.lang = OC.getLanguage();
|
||||
try {
|
||||
this.locale = OC.getLocale();
|
||||
} catch (e) {
|
||||
if (e instanceof TypeError) {
|
||||
this.locale = this.lang;
|
||||
} else {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
moment.locale(this.locale);
|
||||
this.longDateFormat = moment.localeData().longDateFormat('L');
|
||||
this.dateTimeFormat = moment.localeData().longDateFormat('L') + ' ' + moment.localeData().longDateFormat('LT');
|
||||
var urlArray = window.location.pathname.split( '/' );
|
||||
|
||||
if (urlArray[urlArray.length - 1] === 'create') {
|
||||
|
@ -258,7 +247,7 @@
|
|||
|
||||
computed: {
|
||||
langShort: function () {
|
||||
return OC.getLanguage().split("-")[0]
|
||||
return this.lang.split("-")[0]
|
||||
},
|
||||
|
||||
title: function() {
|
||||
|
@ -276,8 +265,39 @@
|
|||
} else {
|
||||
return t('polls', 'Create new poll')
|
||||
}
|
||||
},
|
||||
localeData: function () {
|
||||
return moment.localeData(moment.locale(this.locale))
|
||||
},
|
||||
|
||||
expirationDatePicker: function () {
|
||||
return {
|
||||
editable: true,
|
||||
minuteStep: 1,
|
||||
type: 'datetime',
|
||||
lang: this.lang.split("-")[0],
|
||||
format: moment.localeData().longDateFormat('L') + ' ' + moment.localeData().longDateFormat('LT'),
|
||||
placeholder: t('polls', 'Expiration date')
|
||||
}
|
||||
},
|
||||
|
||||
optionDatePicker: function () {
|
||||
return {
|
||||
editable: false,
|
||||
minuteStep: 1,
|
||||
type: 'datetime',
|
||||
format: moment.localeData().longDateFormat('L') + ' ' + moment.localeData().longDateFormat('LT'),
|
||||
lang: this.lang.split("-")[0],
|
||||
placeholder: t('polls', 'Click to add a date'),
|
||||
timePickerOptions: {
|
||||
start: '00:00',
|
||||
step: '00:05',
|
||||
end: '23:55'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
@ -312,12 +332,14 @@
|
|||
},
|
||||
|
||||
addNewPollDate: function (newPollDate) {
|
||||
this.newPollDate = moment(newPollDate);
|
||||
this.poll.options.pollDates.push({
|
||||
id: this.nextPollDateId++,
|
||||
timestamp: moment(newPollDate).unix(),
|
||||
});
|
||||
this.poll.options.pollDates = _.sortBy(this.poll.options.pollDates, 'timestamp');
|
||||
if (newPollDate != null) {
|
||||
this.newPollDate = moment(newPollDate);
|
||||
this.poll.options.pollDates.push({
|
||||
id: this.nextPollDateId++,
|
||||
timestamp: moment(newPollDate).unix(),
|
||||
});
|
||||
this.poll.options.pollDates = _.sortBy(this.poll.options.pollDates, 'timestamp');
|
||||
}
|
||||
},
|
||||
|
||||
addNewPollText: function () {
|
||||
|
@ -378,6 +400,7 @@
|
|||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
#content {
|
||||
display: flex;
|
||||
|
@ -491,10 +514,12 @@
|
|||
border-bottom: 1px solid var(--color-border);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover, &:active {
|
||||
transition: var(--background-dark) 0.3s ease;
|
||||
background-color: var(--color-loading-light); //$hover-color;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
@ -525,7 +550,10 @@
|
|||
.autocomplete {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.configurationsTabView {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#share-list {
|
||||
.user-list {
|
||||
max-height: 180px;
|
||||
|
@ -539,5 +567,4 @@
|
|||
width: 99%;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
/* global Vue, oc_userconfig */
|
||||
<template>
|
||||
<div class="userRow">
|
||||
<div v-show="description" class="description">{{description}}</div>
|
||||
<div class="avatar">
|
||||
<img :src="avatarURL" :width="size" :height="size">
|
||||
</div>
|
||||
<div v-show="nothidden" class="avatar imageplaceholderseed" :data-username="userId" :data-displayname="computedDisplayName" data-seed="Poll users 1">
|
||||
{{ computedDisplayName.toUpperCase().substr(0,1) }}
|
||||
</div>
|
||||
<div class="user">{{ computedDisplayName }}</div>
|
||||
<div class="user-row" :class="type">
|
||||
<div v-show="description" class="description">{{description}}</div>
|
||||
<div class="avatar"><img :src="avatarURL" :width="size" :height="size" :title="computedDisplayName"></div>
|
||||
<div v-show="!onlyAvatar" class="user-name">{{ computedDisplayName }}</div>
|
||||
</div>
|
||||
|
||||
<div class="avatar imageplaceholderseed"</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
onlyAvatar: {
|
||||
default: false
|
||||
},
|
||||
userId: {
|
||||
type: String,
|
||||
default: OC.getCurrentUser().uid
|
||||
|
@ -81,36 +77,33 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.userRow {
|
||||
<style lang="scss">
|
||||
.user-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-grow: 1;
|
||||
align-items: center;
|
||||
margin-left: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
.description {
|
||||
opacity: 0.7;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.avatar {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
.user {
|
||||
margin-left: 8px;
|
||||
opacity: 0.5;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.imageplaceholderseed {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
background-color: rgb(185, 185, 185);
|
||||
color: rgb(255, 255, 255);
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
font-size: 17.6px;
|
||||
|
||||
> div {
|
||||
margin: 0 4px 0 4px;
|
||||
}
|
||||
|
||||
.description {
|
||||
opacity: 0.7;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
opacity: 0.5;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,36 +1,35 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2> {{ t('polls', 'Share with') }}</h2>
|
||||
<div class="autocomplete">
|
||||
<input class="shareWithField"
|
||||
autocomplete="off"
|
||||
type="text"
|
||||
:placeholder="placeholder"
|
||||
v-model="query"
|
||||
@input="onInput"
|
||||
@focus="onInput">
|
||||
|
||||
<transition-group v-show="openList" tag="ul" v-bind:css="false" class="user-list suggestion">
|
||||
<li v-for="(item, index) in sortedSiteusers"
|
||||
v-bind:key="item.displayName"
|
||||
v-bind:data-index="index"
|
||||
class="flex-row"
|
||||
v-on:click="addShare(index, item)">
|
||||
<user-div :user-id="item.id" :display-name="item.displayName" :type="item.type"></user-div>
|
||||
</li>
|
||||
</transition-group>
|
||||
</div>
|
||||
<multiselect
|
||||
v-model="shares"
|
||||
:options="users"
|
||||
:option-height=32
|
||||
:multiple="true"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:preserve-search="true"
|
||||
label="displayName"
|
||||
track-by="id"
|
||||
:preselect-first="true"
|
||||
:placeholder="placeholder">
|
||||
<template slot="selection" slot-scope="{ values, search, isOpen }">
|
||||
<span class="multiselect__single" v-if="values.length && !isOpen">
|
||||
{{ values.length }} users selected
|
||||
</span>
|
||||
</template>
|
||||
<template slot="option" slot-scope="props">
|
||||
<div class="option__desc">
|
||||
<user-div :user-id="props.option.id" :display-name="props.option.displayName" :type="props.option.type"></user-div>
|
||||
</div>
|
||||
</template>
|
||||
</multiselect>
|
||||
|
||||
<transition-group tag="ul" v-bind:css="false" class="shared-list">
|
||||
<li v-for="(item, index) in sortedShares"
|
||||
v-bind:key="item.displayName"
|
||||
v-bind:data-index="index"
|
||||
class="flex-row">
|
||||
<user-div :user-id="item.id" :display-name="item.displayName" :type="item.type"></user-div>
|
||||
|
||||
<div class="flex-row options">
|
||||
<a @click="removeShare(index, item)" class="icon icon-delete svg delete-poll"></a>
|
||||
</div>
|
||||
v-bind:data-index="index">
|
||||
<user-div :user-id="item.id" :display-name="item.displayName" :type="item.type" only-avatar="true"></user-div>
|
||||
</li>
|
||||
</transition-group>
|
||||
</div>
|
||||
|
@ -38,8 +37,13 @@
|
|||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
|
||||
import { Multiselect } from 'nextcloud-vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Multiselect
|
||||
},
|
||||
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String
|
||||
|
@ -52,14 +56,11 @@
|
|||
data: function () {
|
||||
return {
|
||||
query: '',
|
||||
shares: [],
|
||||
users: [],
|
||||
openList: false,
|
||||
siteUsersLoaded: false,
|
||||
siteUsersListOptions: {
|
||||
getUsers: true,
|
||||
getGroups: true,
|
||||
skipUsers: [],
|
||||
skipGroups: []
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -68,54 +69,20 @@
|
|||
this.loadSiteUsers();
|
||||
},
|
||||
|
||||
mounted: function() {
|
||||
document.addEventListener('click', this.handleClickOutside)
|
||||
},
|
||||
|
||||
destroyed: function() {
|
||||
document.removeEventListener('click', this.handleClickOutside)
|
||||
},
|
||||
|
||||
computed: {
|
||||
filteredSiteusers: function() {
|
||||
var vm = this;
|
||||
return this.users.filter(function (item) {
|
||||
return item.displayName.toLowerCase().indexOf(vm.query.toLowerCase()) !== -1
|
||||
})
|
||||
},
|
||||
|
||||
sortedSiteusers: function() {
|
||||
return this.filteredSiteusers.sort(this.sortByDisplayname);
|
||||
},
|
||||
|
||||
sortedShares: function() {
|
||||
return this.activeShares.sort(this.sortByDisplayname);
|
||||
return this.shares.sort(this.sortByDisplayname);
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addShare: function (index, item){
|
||||
this.$emit('add-share', item);
|
||||
this.users.splice(this.users.indexOf(item), 1);
|
||||
},
|
||||
|
||||
removeShare: function (index, item){
|
||||
this.$emit('remove-share', item);
|
||||
this.users.push(item);
|
||||
},
|
||||
|
||||
loadSiteUsers: function () {
|
||||
var vm = this;
|
||||
vm.siteUsersListOptions.skipUsers = [];
|
||||
vm.siteUsersListOptions.skipGroups = [];
|
||||
this.activeShares.forEach(function(item) {
|
||||
if (item.type === 'group') {
|
||||
vm.siteUsersListOptions.skipGroups.push(item.id)
|
||||
} else if (item.type === 'user') {
|
||||
vm.siteUsersListOptions.skipUsers.push(item.id)
|
||||
}
|
||||
});
|
||||
|
||||
axios.post(OC.generateUrl('apps/polls/get/siteusers'), this.siteUsersListOptions)
|
||||
.then((response) => {
|
||||
this.users = response.data.siteusers;
|
||||
|
@ -124,24 +91,75 @@
|
|||
});
|
||||
},
|
||||
|
||||
onInput: function() {
|
||||
this.loadSiteUsers();
|
||||
if (this.query !== '') {
|
||||
this.openList = true;
|
||||
}
|
||||
},
|
||||
|
||||
sortByDisplayname: function (a, b) {
|
||||
if (a.displayName.toLowerCase() < b.displayName.toLowerCase()) return -1;
|
||||
if (a.displayName.toLowerCase() > b.displayName.toLowerCase()) return 1;
|
||||
return 0;
|
||||
},
|
||||
}
|
||||
|
||||
handleClickOutside: function(evt) {
|
||||
if (!this.$el.contains(evt.target)) {
|
||||
this.openList = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.shared-list {
|
||||
display: flex;
|
||||
padding-top: 8px;
|
||||
flex-grow: 0;
|
||||
justify-content: flex-start;
|
||||
|
||||
> li {
|
||||
display: flex;
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
|
||||
div, select {
|
||||
&.multiselect:not(.multiselect-vue), &.multiselect:not(.multiselect-vue) {
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
width: 100%;
|
||||
.multiselect__content-wrapper li > span {
|
||||
height: unset;
|
||||
}
|
||||
.option__desc {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
.multiselect__option--highlight {
|
||||
background: #41b883;
|
||||
outline: none;
|
||||
color: #fff;
|
||||
&::after {
|
||||
content: attr(data-select);
|
||||
background: #41b883;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.multiselect__option--selected {
|
||||
&::after {
|
||||
content: attr(data-selected);
|
||||
color: silver;
|
||||
}
|
||||
&.multiselect__option--highlight {
|
||||
background: #ff6a6a;
|
||||
color: #fff;
|
||||
&::after {
|
||||
background: #ff6a6a;
|
||||
content: attr(data-deselect);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
@ -98,11 +98,7 @@
|
|||
$owner = $poll->getOwner();
|
||||
|
||||
$expiry_style = '';
|
||||
if ($poll->getType() === 0) {
|
||||
$participated = $_['participations'];
|
||||
} else {
|
||||
$participated = $_['participations_text'];
|
||||
}
|
||||
$participated = $_['votes'];
|
||||
$participated_class = 'partic_no';
|
||||
$participated_title = 'You did not vote';
|
||||
$participated_count = count($participated);
|
||||
|
|
Загрузка…
Ссылка в новой задаче