diff --git a/package-lock.json b/package-lock.json
index 6484568b32..e912f30b3f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8247,6 +8247,21 @@
"axios": "^0.19.0"
}
},
+ "nextcloud-router": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/nextcloud-router/-/nextcloud-router-0.0.9.tgz",
+ "integrity": "sha512-w0i4xqFwJJuXNWFf9AB9huCWW5XmwdJHSHa7oXlOLTAvP9WxwU3KCm/mcKy8Eb0cT0ElRPg72HLUxl7oyEWoBQ==",
+ "requires": {
+ "core-js": "^3.1.4"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz",
+ "integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw=="
+ }
+ }
+ },
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
diff --git a/package.json b/package.json
index fd43829a69..0c007bbc7c 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/components/MultiselectTag/MultiselectTag.vue b/src/components/MultiselectTag/MultiselectTag.vue
new file mode 100644
index 0000000000..3f0901270c
--- /dev/null
+++ b/src/components/MultiselectTag/MultiselectTag.vue
@@ -0,0 +1,117 @@
+
+
+
+
+ {{ t('core', 'No results') }}
+
+ {{ tagLabel(scope.option) }}
+
+
+
+
+
diff --git a/src/components/MultiselectTag/api.js b/src/components/MultiselectTag/api.js
new file mode 100644
index 0000000000..f371a4b71d
--- /dev/null
+++ b/src/components/MultiselectTag/api.js
@@ -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: `
+
+
+
+
+
+
+
+
+ `
+ }).then((response) => {
+ return xmlToTagList(response.data)
+ })
+}
+
+export {
+ searchTags
+}
diff --git a/src/components/MultiselectTag/index.js b/src/components/MultiselectTag/index.js
new file mode 100644
index 0000000000..69b7e277e7
--- /dev/null
+++ b/src/components/MultiselectTag/index.js
@@ -0,0 +1,4 @@
+import MultiselectTag from './MultiselectTag'
+
+export default MultiselectTag
+export { MultiselectTag }
diff --git a/src/components/index.js b/src/components/index.js
index 6b11cc7230..181cf3aaaf 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -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 {
@@ -73,5 +74,6 @@ export {
DatetimePicker,
Modal,
Multiselect,
+ MultiselectTag,
PopoverMenu
}