2021-05-30 20:30:08 +02:00
|
|
|
<template>
|
2021-07-05 12:29:04 +02:00
|
|
|
<modal v-if="active" class="quick-actions" @close="closeQuickActions" :overflow="isNewTaskCommand">
|
2021-05-30 20:30:08 +02:00
|
|
|
<div class="card">
|
|
|
|
<div class="action-input" :class="{'has-active-cmd': selectedCmd !== null}">
|
|
|
|
<div class="active-cmd tag" v-if="selectedCmd !== null">
|
|
|
|
{{ selectedCmd.title }}
|
|
|
|
</div>
|
|
|
|
<input
|
|
|
|
v-focus
|
|
|
|
class="input"
|
|
|
|
:class="{'is-loading': loading}"
|
|
|
|
v-model="query"
|
|
|
|
:placeholder="placeholder"
|
|
|
|
@keyup="search"
|
|
|
|
ref="searchInput"
|
|
|
|
@keydown.down.prevent="() => select(0, 0)"
|
|
|
|
@keyup.prevent.delete="unselectCmd"
|
|
|
|
@keyup.prevent.enter="doCmd"
|
|
|
|
@keyup.prevent.esc="closeQuickActions"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
2021-07-05 12:29:04 +02:00
|
|
|
<div class="help has-text-grey-light p-2" v-if="hintText !== '' && !isNewTaskCommand">
|
2021-05-30 20:30:08 +02:00
|
|
|
{{ hintText }}
|
|
|
|
</div>
|
|
|
|
|
2021-07-05 12:29:04 +02:00
|
|
|
<quick-add-magic class="p-2 modal-container-smaller" v-if="isNewTaskCommand"/>
|
|
|
|
|
2021-05-30 20:30:08 +02:00
|
|
|
<div class="results" v-if="selectedCmd === null">
|
|
|
|
<div v-for="(r, k) in results" :key="k" class="result">
|
|
|
|
<span class="result-title">
|
|
|
|
{{ r.title }}
|
|
|
|
</span>
|
|
|
|
<div class="result-items">
|
|
|
|
<button
|
|
|
|
v-for="(i, key) in r.items"
|
|
|
|
:key="key"
|
|
|
|
:ref="`result-${k}_${key}`"
|
|
|
|
@keydown.up.prevent="() => select(k, key - 1)"
|
|
|
|
@keydown.down.prevent="() => select(k, key + 1)"
|
|
|
|
@click.prevent.stop="() => doAction(r.type, i)"
|
|
|
|
@keyup.prevent.enter="() => doAction(r.type, i)"
|
|
|
|
@keyup.prevent.esc="() => $refs.searchInput.focus()"
|
2021-07-06 15:08:55 +02:00
|
|
|
:class="{'is-strikethrough': i.done}"
|
2021-05-30 20:30:08 +02:00
|
|
|
>
|
|
|
|
{{ i.title }}
|
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</modal>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import TaskService from '@/services/task'
|
|
|
|
import TeamService from '@/services/team'
|
|
|
|
|
|
|
|
import NamespaceModel from '@/models/namespace'
|
|
|
|
import TeamModel from '@/models/team'
|
|
|
|
|
2021-06-24 15:38:25 +02:00
|
|
|
import {CURRENT_LIST, LOADING, LOADING_MODULE, QUICK_ACTIONS_ACTIVE} from '@/store/mutation-types'
|
2021-05-30 20:30:08 +02:00
|
|
|
import ListModel from '@/models/list'
|
2021-07-05 12:29:04 +02:00
|
|
|
import createTask from '@/components/tasks/mixins/createTask'
|
|
|
|
import QuickAddMagic from '@/components/tasks/partials/quick-add-magic'
|
2021-05-30 20:30:08 +02:00
|
|
|
|
|
|
|
const TYPE_LIST = 'list'
|
|
|
|
const TYPE_TASK = 'task'
|
|
|
|
const TYPE_CMD = 'cmd'
|
|
|
|
const TYPE_TEAM = 'team'
|
|
|
|
|
|
|
|
const CMD_NEW_TASK = 'newTask'
|
|
|
|
const CMD_NEW_LIST = 'newList'
|
|
|
|
const CMD_NEW_NAMESPACE = 'newNamespace'
|
|
|
|
const CMD_NEW_TEAM = 'newTeam'
|
|
|
|
|
2021-06-03 14:20:26 +02:00
|
|
|
const SEARCH_MODE_ALL = 'all'
|
|
|
|
const SEARCH_MODE_TASKS = 'tasks'
|
|
|
|
const SEARCH_MODE_LISTS = 'lists'
|
|
|
|
const SEARCH_MODE_TEAMS = 'teams'
|
|
|
|
|
2021-05-30 20:30:08 +02:00
|
|
|
export default {
|
|
|
|
name: 'quick-actions',
|
2021-07-05 12:29:04 +02:00
|
|
|
components: {QuickAddMagic},
|
2021-05-30 20:30:08 +02:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
query: '',
|
|
|
|
selectedCmd: null,
|
|
|
|
|
|
|
|
foundTasks: [],
|
|
|
|
taskSearchTimeout: null,
|
|
|
|
taskService: null,
|
|
|
|
|
|
|
|
foundTeams: [],
|
2021-06-03 14:20:26 +02:00
|
|
|
teamSearchTimeout: null,
|
2021-05-30 20:30:08 +02:00
|
|
|
teamService: null,
|
|
|
|
}
|
|
|
|
},
|
2021-07-05 12:29:04 +02:00
|
|
|
mixins: [
|
|
|
|
createTask,
|
|
|
|
],
|
2021-05-30 20:30:08 +02:00
|
|
|
computed: {
|
|
|
|
active() {
|
|
|
|
const active = this.$store.state[QUICK_ACTIONS_ACTIVE]
|
|
|
|
if (!active) {
|
|
|
|
this.reset()
|
|
|
|
}
|
|
|
|
return active
|
|
|
|
},
|
|
|
|
results() {
|
2021-06-03 14:20:26 +02:00
|
|
|
let lists = []
|
|
|
|
if (this.searchMode === SEARCH_MODE_ALL || this.searchMode === SEARCH_MODE_LISTS) {
|
|
|
|
let query = this.query
|
|
|
|
if (this.searchMode === SEARCH_MODE_LISTS) {
|
|
|
|
query = query.substr(1)
|
|
|
|
}
|
|
|
|
|
2021-07-06 15:00:31 +02:00
|
|
|
const ncache = {}
|
|
|
|
|
2021-06-03 14:20:26 +02:00
|
|
|
lists = (Object.values(this.$store.state.lists).filter(l => {
|
2021-07-06 15:00:31 +02:00
|
|
|
if (l.isArchived) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof ncache[l.namespaceId] === 'undefined') {
|
|
|
|
ncache[l.namespaceId] = this.$store.getters['namespaces/getNamespaceById'](l.namespaceId)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ncache[l.namespaceId].isArchived) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-06-03 14:20:26 +02:00
|
|
|
return l.title.toLowerCase().includes(query.toLowerCase())
|
|
|
|
}) ?? [])
|
|
|
|
}
|
2021-05-30 20:30:08 +02:00
|
|
|
|
|
|
|
const cmds = this.availableCmds
|
|
|
|
.filter(a => a.title.toLowerCase().includes(this.query.toLowerCase()))
|
|
|
|
|
|
|
|
return [
|
|
|
|
{
|
|
|
|
type: TYPE_CMD,
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.commands'),
|
2021-05-30 20:30:08 +02:00
|
|
|
items: cmds,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: TYPE_TASK,
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.tasks'),
|
2021-05-30 20:30:08 +02:00
|
|
|
items: this.foundTasks,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: TYPE_LIST,
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.lists'),
|
2021-05-30 20:30:08 +02:00
|
|
|
items: lists,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: TYPE_TEAM,
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.teams'),
|
2021-05-30 20:30:08 +02:00
|
|
|
items: this.foundTeams,
|
|
|
|
},
|
|
|
|
].filter(i => i.items.length > 0)
|
|
|
|
},
|
|
|
|
nothing() {
|
|
|
|
return this.search === '' || Object.keys(this.results).length === 0
|
|
|
|
},
|
|
|
|
loading() {
|
|
|
|
return this.taskService.loading ||
|
2021-06-24 15:38:25 +02:00
|
|
|
(this.$store.state[LOADING] && this.$store.state[LOADING_MODULE] === 'namespaces') ||
|
|
|
|
(this.$store.state[LOADING] && this.$store.state[LOADING_MODULE] === 'lists') ||
|
2021-05-30 20:30:08 +02:00
|
|
|
this.teamService.loading
|
|
|
|
},
|
|
|
|
placeholder() {
|
|
|
|
if (this.selectedCmd !== null) {
|
|
|
|
switch (this.selectedCmd.action) {
|
|
|
|
case CMD_NEW_TASK:
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.newTask')
|
2021-05-30 20:30:08 +02:00
|
|
|
case CMD_NEW_LIST:
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.newList')
|
2021-05-30 20:30:08 +02:00
|
|
|
case CMD_NEW_NAMESPACE:
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.newNamespace')
|
2021-05-30 20:30:08 +02:00
|
|
|
case CMD_NEW_TEAM:
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.newTeam')
|
2021-05-30 20:30:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.placeholder')
|
2021-05-30 20:30:08 +02:00
|
|
|
},
|
|
|
|
hintText() {
|
|
|
|
let namespace
|
|
|
|
|
|
|
|
if (this.selectedCmd !== null && this.currentList !== null) {
|
|
|
|
switch (this.selectedCmd.action) {
|
|
|
|
case CMD_NEW_TASK:
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.createTask', {title: this.currentList.title})
|
2021-05-30 20:30:08 +02:00
|
|
|
case CMD_NEW_LIST:
|
|
|
|
namespace = this.$store.getters['namespaces/getNamespaceById'](this.currentList.namespaceId)
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.createList', {title: namespace.title})
|
2021-05-30 20:30:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-24 01:24:57 +02:00
|
|
|
return this.$t('quickActions.hint')
|
2021-05-30 20:30:08 +02:00
|
|
|
},
|
|
|
|
currentList() {
|
|
|
|
return Object.keys(this.$store.state[CURRENT_LIST]).length === 0 ? null : this.$store.state[CURRENT_LIST]
|
|
|
|
},
|
|
|
|
availableCmds() {
|
|
|
|
const cmds = []
|
|
|
|
|
|
|
|
if (this.currentList !== null) {
|
|
|
|
cmds.push({
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.cmds.newTask'),
|
2021-05-30 20:30:08 +02:00
|
|
|
action: CMD_NEW_TASK,
|
|
|
|
})
|
|
|
|
cmds.push({
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.cmds.newList'),
|
2021-05-30 20:30:08 +02:00
|
|
|
action: CMD_NEW_LIST,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
cmds.push({
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.cmds.newNamespace'),
|
2021-05-30 20:30:08 +02:00
|
|
|
action: CMD_NEW_NAMESPACE,
|
|
|
|
})
|
|
|
|
cmds.push({
|
2021-06-24 01:24:57 +02:00
|
|
|
title: this.$t('quickActions.cmds.newTeam'),
|
2021-05-30 20:30:08 +02:00
|
|
|
action: CMD_NEW_TEAM,
|
|
|
|
})
|
|
|
|
|
|
|
|
return cmds
|
|
|
|
},
|
2021-06-03 14:20:26 +02:00
|
|
|
searchMode() {
|
|
|
|
if (this.query === '') {
|
|
|
|
return SEARCH_MODE_ALL
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.query.startsWith('#')) {
|
|
|
|
return SEARCH_MODE_TASKS
|
|
|
|
}
|
|
|
|
if (this.query.startsWith('*')) {
|
|
|
|
return SEARCH_MODE_LISTS
|
|
|
|
}
|
|
|
|
if (this.query.startsWith('@')) {
|
|
|
|
return SEARCH_MODE_TEAMS
|
|
|
|
}
|
|
|
|
|
|
|
|
return SEARCH_MODE_ALL
|
|
|
|
},
|
2021-07-05 12:29:04 +02:00
|
|
|
isNewTaskCommand() {
|
|
|
|
return this.selectedCmd !== null && this.selectedCmd.action === CMD_NEW_TASK
|
|
|
|
},
|
2021-05-30 20:30:08 +02:00
|
|
|
},
|
|
|
|
created() {
|
|
|
|
this.taskService = new TaskService()
|
|
|
|
this.teamService = new TeamService()
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
search() {
|
|
|
|
this.searchTasks()
|
2021-06-03 14:20:26 +02:00
|
|
|
this.searchTeams()
|
2021-05-30 20:30:08 +02:00
|
|
|
},
|
|
|
|
searchTasks() {
|
2021-06-03 14:20:26 +02:00
|
|
|
if (this.searchMode !== SEARCH_MODE_ALL && this.searchMode !== SEARCH_MODE_TASKS) {
|
|
|
|
this.foundTasks = []
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let query = this.query
|
|
|
|
if (this.searchMode === SEARCH_MODE_TASKS) {
|
|
|
|
query = query.substr(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query === '' || this.selectedCmd !== null) {
|
2021-05-30 20:30:08 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.taskSearchTimeout !== null) {
|
|
|
|
clearTimeout(this.taskSearchTimeout)
|
|
|
|
this.taskSearchTimeout = null
|
|
|
|
}
|
|
|
|
|
|
|
|
this.taskSearchTimeout = setTimeout(() => {
|
2021-06-03 14:20:26 +02:00
|
|
|
this.taskService.getAll({}, {s: query})
|
2021-05-30 20:30:08 +02:00
|
|
|
.then(r => {
|
|
|
|
r = r.map(t => {
|
|
|
|
t.type = TYPE_TASK
|
|
|
|
const list = this.$store.getters['lists/getListById'](t.listId) === null ? null : this.$store.getters['lists/getListById'](t.listId)
|
|
|
|
if (list !== null) {
|
|
|
|
t.title = `${t.title} (${list.title})`
|
|
|
|
}
|
|
|
|
|
|
|
|
return t
|
|
|
|
})
|
|
|
|
this.$set(this, 'foundTasks', r)
|
|
|
|
})
|
|
|
|
}, 150)
|
|
|
|
},
|
2021-06-03 14:20:26 +02:00
|
|
|
searchTeams() {
|
|
|
|
if (this.searchMode !== SEARCH_MODE_ALL && this.searchMode !== SEARCH_MODE_TEAMS) {
|
|
|
|
this.foundTeams = []
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let query = this.query
|
|
|
|
if (this.searchMode === SEARCH_MODE_TEAMS) {
|
|
|
|
query = query.substr(1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query === '' || this.selectedCmd !== null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.teamSearchTimeout !== null) {
|
|
|
|
clearTimeout(this.teamSearchTimeout)
|
|
|
|
this.teamSearchTimeout = null
|
|
|
|
}
|
|
|
|
|
|
|
|
this.teamSearchTimeout = setTimeout(() => {
|
|
|
|
this.teamService.getAll({}, {s: query})
|
|
|
|
.then(r => {
|
|
|
|
r = r.map(t => {
|
|
|
|
t.title = t.name
|
|
|
|
return t
|
|
|
|
})
|
|
|
|
this.$set(this, 'foundTeams', r)
|
|
|
|
})
|
|
|
|
}, 150)
|
|
|
|
},
|
2021-05-30 20:30:08 +02:00
|
|
|
closeQuickActions() {
|
|
|
|
this.$store.commit(QUICK_ACTIONS_ACTIVE, false)
|
|
|
|
},
|
|
|
|
doAction(type, item) {
|
|
|
|
switch (type) {
|
|
|
|
case TYPE_LIST:
|
|
|
|
this.$router.push({name: 'list.index', params: {listId: item.id}})
|
|
|
|
this.closeQuickActions()
|
|
|
|
break
|
|
|
|
case TYPE_TASK:
|
|
|
|
this.$router.push({name: 'task.detail', params: {id: item.id}})
|
|
|
|
this.closeQuickActions()
|
|
|
|
break
|
|
|
|
case TYPE_CMD:
|
|
|
|
this.query = ''
|
|
|
|
this.selectedCmd = item
|
|
|
|
this.$refs.searchInput.focus()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
},
|
|
|
|
doCmd() {
|
|
|
|
if (this.selectedCmd === null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.query === '') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (this.selectedCmd.action) {
|
|
|
|
case CMD_NEW_TASK:
|
|
|
|
this.newTask()
|
|
|
|
break
|
|
|
|
case CMD_NEW_LIST:
|
|
|
|
this.newList()
|
|
|
|
break
|
|
|
|
case CMD_NEW_NAMESPACE:
|
|
|
|
this.newNamespace()
|
|
|
|
break
|
|
|
|
case CMD_NEW_TEAM:
|
|
|
|
this.newTeam()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
},
|
|
|
|
newTask() {
|
|
|
|
if (this.currentList === null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-07-05 12:29:04 +02:00
|
|
|
this.createNewTask(this.query, 0, this.currentList.id)
|
2021-05-30 20:30:08 +02:00
|
|
|
.then(r => {
|
2021-06-24 01:24:57 +02:00
|
|
|
this.success({message: this.$t('task.createSuccess')})
|
2021-05-30 20:30:08 +02:00
|
|
|
this.$router.push({name: 'task.detail', params: {id: r.id}})
|
|
|
|
this.closeQuickActions()
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
2021-06-22 22:07:57 +02:00
|
|
|
this.error(e)
|
2021-05-30 20:30:08 +02:00
|
|
|
})
|
|
|
|
},
|
|
|
|
newList() {
|
|
|
|
if (this.currentList === null) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
const newList = new ListModel({
|
|
|
|
title: this.query,
|
|
|
|
namespaceId: this.currentList.namespaceId,
|
|
|
|
})
|
2021-06-24 15:38:25 +02:00
|
|
|
this.$store.dispatch('lists/createList', newList)
|
2021-05-30 20:30:08 +02:00
|
|
|
.then(r => {
|
2021-06-24 01:24:57 +02:00
|
|
|
this.success({message: this.$t('list.create.createdSuccess')})
|
2021-05-30 20:30:08 +02:00
|
|
|
this.$router.push({name: 'list.index', params: {listId: r.id}})
|
|
|
|
this.closeQuickActions()
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
2021-06-22 22:07:57 +02:00
|
|
|
this.error(e)
|
2021-05-30 20:30:08 +02:00
|
|
|
})
|
|
|
|
},
|
|
|
|
newNamespace() {
|
|
|
|
const newNamespace = new NamespaceModel({title: this.query})
|
2021-06-24 15:38:25 +02:00
|
|
|
|
|
|
|
this.$store.dispatch('namespaces/createNamespace', newNamespace)
|
|
|
|
.then(() => {
|
2021-06-24 01:24:57 +02:00
|
|
|
this.success({message: this.$t('namespace.create.success')})
|
2021-05-30 20:30:08 +02:00
|
|
|
this.closeQuickActions()
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
2021-06-22 22:07:57 +02:00
|
|
|
this.error(e)
|
2021-05-30 20:30:08 +02:00
|
|
|
})
|
|
|
|
},
|
|
|
|
newTeam() {
|
|
|
|
const newTeam = new TeamModel({name: this.query})
|
|
|
|
this.teamService.create(newTeam)
|
|
|
|
.then(r => {
|
|
|
|
this.$router.push({
|
|
|
|
name: 'teams.edit',
|
|
|
|
params: {id: r.id},
|
|
|
|
})
|
2021-06-24 01:24:57 +02:00
|
|
|
this.success({message: this.$t('team.create.success')})
|
2021-05-30 20:30:08 +02:00
|
|
|
this.closeQuickActions()
|
|
|
|
})
|
|
|
|
.catch((e) => {
|
2021-06-22 22:07:57 +02:00
|
|
|
this.error(e)
|
2021-05-30 20:30:08 +02:00
|
|
|
})
|
|
|
|
},
|
|
|
|
select(parentIndex, index) {
|
|
|
|
|
|
|
|
if (index < 0 && parentIndex === 0) {
|
|
|
|
this.$refs.searchInput.focus()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 0) {
|
|
|
|
parentIndex--
|
|
|
|
index = this.results[parentIndex].items.length - 1
|
|
|
|
}
|
|
|
|
|
|
|
|
let elems = this.$refs[`result-${parentIndex}_${index}`]
|
|
|
|
|
|
|
|
if (this.results[parentIndex].items.length === index) {
|
|
|
|
elems = this.$refs[`result-${parentIndex + 1}_0`]
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof elems === 'undefined' || elems.length === 0) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Array.isArray(elems)) {
|
|
|
|
elems[0].focus()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
elems.focus()
|
|
|
|
},
|
|
|
|
unselectCmd() {
|
|
|
|
if (this.query !== '') {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.selectedCmd = null
|
|
|
|
},
|
|
|
|
reset() {
|
|
|
|
this.query = ''
|
|
|
|
this.selectedCmd = null
|
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
</script>
|