Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add tags component
Signed-off-by: Julius Härtl <[email protected]>
  • Loading branch information
juliusknorr committed Sep 2, 2019
commit 2c07586f293a07ff97b37608ec51d547f9006282
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"hammerjs": "^2.0.8",
"md5": "^2.2.1",
"nextcloud-axios": "^0.2.0",
"nextcloud-router": "0.0.9",
"v-tooltip": "^2.0.0-rc.33",
"vue": "^2.6.7",
"vue-click-outside": "^1.0.7",
Expand Down
117 changes: 117 additions & 0 deletions src/components/MultiselectTag/MultiselectTag.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<!--
- @copyright Copyright (c) 2019 Julius Härtl <[email protected]>
-
- @author Julius Härtl <[email protected]>
-
- @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>
<Multiselect v-model="inputValObjects"
:options="tags" :options-limit="5"
:placeholder="label"
track-by="id"
:custom-label="tagLabel"
class="multiselect-vue" :multiple="multiple"
:close-on-select="false" :tag-width="60"
:disabled="disabled" @input="update"
@search-change="asyncFind">
<span slot="noResult">{{ t('core', 'No results') }}</span>
<template #option="scope">
{{ tagLabel(scope.option) }}
</template>
</multiselect>
</template>

<script>
import Multiselect from 'Components/Multiselect'
import { searchTags } from './api'

let uuid = 0
export default {
name: 'MultiselectTag',
components: {
Multiselect
},
props: {
label: {
type: String,
required: true
},
value: {
type: Array,
default: () => []
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: true
}
},
data() {
return {
inputValObjects: [],
tags: []
}
},
computed: {
id() {
return 'settings-input-text-' + this.uuid
}
},
watch: {
value(newVal) {
this.inputValObjects = this.getValueObject()
}
},
beforeCreate: function() {
this.uuid = uuid.toString()
uuid += 1
searchTags().then((result) => {
this.tags = result
this.inputValObjects = this.getValueObject()
})
},
methods: {
asyncFind(query) {
},
getValueObject() {
if (this.multiple) {
return this.value.filter((tag) => tag !== '').map(
(id) => this.tags.find((tag) => tag.id === id)
)
}
return this.tags.find((tag) => tag.id === this.value)
},
update() {
this.$emit('input', this.inputValObjects.map((element) => element.id))
},
tagLabel({ displayName, userVisible, userAssignable }) {
if (userVisible === false) {
return `${displayName} (invisible)`
}
if (userAssignable === false) {
return `${displayName} (restricted)`
}
return displayName
}
}
}
</script>
90 changes: 90 additions & 0 deletions src/components/MultiselectTag/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import axios from 'nextcloud-axios'
import { generateRemoteUrl } from 'nextcloud-router'

const xmlToJson = (xml) => {
let obj = {}

if (xml.nodeType === 1) {
if (xml.attributes.length > 0) {
obj['@attributes'] = {}
for (let j = 0; j < xml.attributes.length; j++) {
const attribute = xml.attributes.item(j)
obj['@attributes'][attribute.nodeName] = attribute.nodeValue
}
}
} else if (xml.nodeType === 3) {
obj = xml.nodeValue
}

if (xml.hasChildNodes()) {
for (let i = 0; i < xml.childNodes.length; i++) {
const item = xml.childNodes.item(i)
const nodeName = item.nodeName
if (typeof (obj[nodeName]) === 'undefined') {
obj[nodeName] = xmlToJson(item)
} else {
if (typeof obj[nodeName].push === 'undefined') {
var old = obj[nodeName]
obj[nodeName] = []
obj[nodeName].push(old)
}
obj[nodeName].push(xmlToJson(item))
}
}
}
return obj
}

const parseXml = (xml) => {
let dom = null
try {
dom = (new DOMParser()).parseFromString(xml, 'text/xml')
} catch (e) {
console.error('Failed to parse xml document', e)
}
return dom
}

const xmlToTagList = (xml) => {
let json = xmlToJson(parseXml(xml))
let list = json['d:multistatus']['d:response']
let result = []
for (let index in list) {
let tag = list[index]['d:propstat']

if (tag['d:status']['#text'] !== 'HTTP/1.1 200 OK') {
continue
}
result.push({
id: tag['d:prop']['oc:id']['#text'],
displayName: tag['d:prop']['oc:display-name']['#text'],
canAssign: tag['d:prop']['oc:can-assign']['#text'] === 'true',
userAssignable: tag['d:prop']['oc:user-assignable']['#text'] === 'true',
userVisible: tag['d:prop']['oc:user-visible']['#text'] === 'true'
})
}
return result
}

const searchTags = function() {
return axios({
method: 'PROPFIND',
url: generateRemoteUrl('dav') + '/systemtags/',
data: `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:id />
<oc:display-name />
<oc:user-visible />
<oc:user-assignable />
<oc:can-assign />
</d:prop>
</d:propfind>`
}).then((response) => {
return xmlToTagList(response.data)
})
}

export {
searchTags
}
4 changes: 4 additions & 0 deletions src/components/MultiselectTag/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import MultiselectTag from './MultiselectTag'

export default MultiselectTag
export { MultiselectTag }
2 changes: 2 additions & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import Content from './Content'
import DatetimePicker from './DatetimePicker'
import Modal from './Modal'
import Multiselect from './Multiselect'
import MultiselectTag from './MultiselectTag'
import PopoverMenu from './PopoverMenu'

export {
Expand Down Expand Up @@ -73,5 +74,6 @@ export {
DatetimePicker,
Modal,
Multiselect,
MultiselectTag,
PopoverMenu
}