UNPKG

@nextcloud/vue

Version:
1 lines 15.6 kB
{"version":3,"file":"NcSelectTags.cjs","sources":["../../src/components/NcSelectTags/api.js","../../src/components/NcSelectTags/NcSelectTags.vue"],"sourcesContent":["/**\n * @copyright Copyright (c) 2019 Julius Härtl <jus@bitgrid.net>\n *\n * @author Julius Härtl <jus@bitgrid.net>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport axios from '@nextcloud/axios'\nimport { generateRemoteUrl } from '@nextcloud/router'\n\nconst xmlToJson = (xml) => {\n\tlet obj = {}\n\n\tif (xml.nodeType === 1) {\n\t\tif (xml.attributes.length > 0) {\n\t\t\tobj['@attributes'] = {}\n\t\t\tfor (let j = 0; j < xml.attributes.length; j++) {\n\t\t\t\tconst attribute = xml.attributes.item(j)\n\t\t\t\tobj['@attributes'][attribute.nodeName] = attribute.nodeValue\n\t\t\t}\n\t\t}\n\t} else if (xml.nodeType === 3) {\n\t\tobj = xml.nodeValue\n\t}\n\n\tif (xml.hasChildNodes()) {\n\t\tfor (let i = 0; i < xml.childNodes.length; i++) {\n\t\t\tconst item = xml.childNodes.item(i)\n\t\t\tconst nodeName = item.nodeName\n\t\t\tif (typeof (obj[nodeName]) === 'undefined') {\n\t\t\t\tobj[nodeName] = xmlToJson(item)\n\t\t\t} else {\n\t\t\t\tif (typeof obj[nodeName].push === 'undefined') {\n\t\t\t\t\tconst old = obj[nodeName]\n\t\t\t\t\tobj[nodeName] = []\n\t\t\t\t\tobj[nodeName].push(old)\n\t\t\t\t}\n\t\t\t\tobj[nodeName].push(xmlToJson(item))\n\t\t\t}\n\t\t}\n\t}\n\treturn obj\n}\n\nconst parseXml = (xml) => {\n\tlet dom = null\n\ttry {\n\t\tdom = (new DOMParser()).parseFromString(xml, 'text/xml')\n\t} catch (e) {\n\t\tconsole.error('Failed to parse xml document', e)\n\t}\n\treturn dom\n}\n\nconst xmlToTagList = (xml) => {\n\tconst json = xmlToJson(parseXml(xml))\n\tconst list = json['d:multistatus']['d:response']\n\tconst result = []\n\tfor (const index in list) {\n\t\tconst tag = list[index]['d:propstat']\n\n\t\tif (tag['d:status']['#text'] !== 'HTTP/1.1 200 OK') {\n\t\t\tcontinue\n\t\t}\n\t\tresult.push({\n\t\t\tid: parseInt(tag['d:prop']['oc:id']['#text']),\n\t\t\tdisplayName: tag['d:prop']['oc:display-name']['#text'],\n\t\t\tcanAssign: tag['d:prop']['oc:can-assign']['#text'] === 'true',\n\t\t\tuserAssignable: tag['d:prop']['oc:user-assignable']['#text'] === 'true',\n\t\t\tuserVisible: tag['d:prop']['oc:user-visible']['#text'] === 'true',\n\t\t})\n\t}\n\treturn result\n}\n\nconst searchTags = async function() {\n\tif (window.NextcloudVueDocs) {\n\t\treturn Promise.resolve(xmlToTagList(window.NextcloudVueDocs.tags))\n\t}\n\n\tconst result = await axios({\n\t\tmethod: 'PROPFIND',\n\t\turl: generateRemoteUrl('dav') + '/systemtags/',\n\t\tdata: `<?xml version=\"1.0\"?>\n\t\t\t\t\t<d:propfind xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\">\n\t\t\t\t\t <d:prop>\n\t\t\t\t\t\t<oc:id />\n\t\t\t\t\t\t<oc:display-name />\n\t\t\t\t\t\t<oc:user-visible />\n\t\t\t\t\t\t<oc:user-assignable />\n\t\t\t\t\t\t<oc:can-assign />\n\t\t\t\t\t </d:prop>\n\t\t\t\t\t</d:propfind>`,\n\t})\n\treturn xmlToTagList(result.data)\n}\n\nexport {\n\tsearchTags,\n}\n","<!--\n - @copyright 2022 Christopher Ng <chrng8@gmail.com>\n -\n - @author Christopher Ng <chrng8@gmail.com>\n - @author Julius Härtl <jus@bitgrid.net>\n -\n - @license AGPL-3.0-or-later\n -\n - This program is free software: you can redistribute it and/or modify\n - it under the terms of the GNU Affero General Public License as\n - published by the Free Software Foundation, either version 3 of the\n - License, or (at your option) any later version.\n -\n - This program is distributed in the hope that it will be useful,\n - but WITHOUT ANY WARRANTY; without even the implied warranty of\n - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n - GNU Affero General Public License for more details.\n -\n - You should have received a copy of the GNU Affero General Public License\n - along with this program. If not, see <http://www.gnu.org/licenses/>.\n -\n-->\n\n<docs>\n### Single tag selector\n\n```vue\n<template>\n\t<div class=\"wrapper\">\n\t\t<NcSelectTags v-model=\"value\" :multiple=\"false\" />\n\t\t{{ value }}\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tvalue: 1,\n\t\t}\n\t}\n}\n</script>\n```\n\n### Multiple tag selector\n```vue\n<template>\n\t<div class=\"wrapper\">\n\t\t<NcSelectTags v-model=\"value\" :multiple=\"true\" />\n\t\t{{ value }}\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tvalue: [\n\t\t\t\t1,\n\t\t\t\t2,\n\t\t\t],\n\t\t}\n\t}\n}\n</script>\n```\n\n### Custom filter\nBecause of compatibility reasons only 5 tag entries are shown by default. If you want to show all available tags set the `limit` prop to `null`:\n```vue\n<template>\n\t<div class=\"wrapper\">\n\t\t<NcSelectTags v-model=\"value\" :limit=\"null\" />\n\t\t{{ value }}\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tvalue: [\n\t\t\t\t1,\n\t\t\t\t2,\n\t\t\t],\n\t\t}\n\t}\n}\n</script>\n```\n\nIt's also possible to apply any custom filter logic by setting the `optionsFilter` function-prop to any custom function receiving the tag element and the index:\n```vue\n<template>\n\t<div class=\"wrapper\">\n\t\t<NcSelectTags v-model=\"value\" :options-filter=\"customFilter\" />\n\t\t{{ value }}\n\t</div>\n</template>\n\n<script>\nexport default {\n\tdata() {\n\t\treturn {\n\t\t\tvalue: [\n\t\t\t\t3,\n\t\t\t],\n\t\t}\n\t},\n\tmethods: {\n\t\t/**\n\t\t* Implement your custom filter logic to filter tags delivered\n\t\t* by the server\n\t\t*\n\t\t* @param {object} the tag object\n\t\t* @param {int} the index of the object inside the collection\n\t\t*/\n\t\tcustomFilter(element, index) {\n\t\t\t/*\n\t\t\t* Tag objects returned by the server will have the\n\t\t\t* following properties (see also api.js):\n\t\t\t* id, displayName, canAssign, userAssignable, userVisible\n\t\t\t*/\n\t\t\treturn element.id >= 2 && element.displayName !== '' && element.canAssign && element.userAssignable && element.userVisible\n\t\t}\n\t}\n}\n</script>\n```\n</docs>\n\n<template>\n\t<NcSelect v-bind=\"propsToForward\"\n\t\t:options=\"availableOptions\"\n\t\t:close-on-select=\"!multiple\"\n\t\t:value=\"passthru ? value : localValue\"\n\t\t@search=\"searchString => search = searchString\"\n\t\tv-on=\"{\n\t\t\t...$listeners,\n\t\t\tinput: passthru ? $listeners.input : handleInput,\n\t\t}\">\n\t\t<template #option=\"option\">\n\t\t\t<NcEllipsisedOption :name=\"getOptionLabel(option)\"\n\t\t\t\t:search=\"search\" />\n\t\t</template>\n\t\t<template #selected-option=\"selectedOption\">\n\t\t\t<NcEllipsisedOption :name=\"getOptionLabel(selectedOption)\"\n\t\t\t\t:search=\"search\" />\n\t\t</template>\n\t\t<template v-for=\"(_, name) in $scopedSlots\" #[name]=\"data\">\n\t\t\t<!-- @slot Any combination of slots from https://vue-select.org/api/slots.html -->\n\t\t\t<slot :name=\"name\" v-bind=\"data\" />\n\t\t</template>\n\t</NcSelect>\n</template>\n\n<script>\nimport NcEllipsisedOption from '../NcEllipsisedOption/index.js'\nimport NcSelect from '../NcSelect/index.js'\n\nimport { searchTags } from './api.js'\nimport { t } from '../../l10n.js'\n\nexport default {\n\tname: 'NcSelectTags',\n\n\tcomponents: {\n\t\tNcEllipsisedOption,\n\t\tNcSelect,\n\t},\n\n\tprops: {\n\t\t// Add NcSelect prop defaults and populate $props\n\t\t...NcSelect.props,\n\n\t\t/**\n\t\t * Enable automatic fetching of tags\n\t\t *\n\t\t * If `false`, available tags must be passed using the `options` prop\n\t\t */\n\t\tfetchTags: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Callback to generate the label text\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#getoptionlabel\n\t\t */\n\t\tgetOptionLabel: {\n\t\t\ttype: Function,\n\t\t\tdefault: (option) => {\n\t\t\t\tconst { displayName, userVisible, userAssignable } = option\n\t\t\t\tif (userVisible === false) {\n\t\t\t\t\treturn t('{tag} (invisible)', { tag: displayName })\n\t\t\t\t}\n\t\t\t\tif (userAssignable === false) {\n\t\t\t\t\treturn t('{tag} (restricted)', { tag: displayName })\n\t\t\t\t}\n\t\t\t\treturn displayName\n\t\t\t},\n\t\t},\n\n\t\t/**\n\t\t * Sets the maximum number of tags to display in the dropdown list\n\t\t *\n\t\t * Because of compatibility reasons only 5 tag entries are shown by\n\t\t * default\n\t\t */\n\t\tlimit: {\n\t\t\ttype: Number,\n\t\t\tdefault: 5,\n\t\t},\n\n\t\t/**\n\t\t * Allow selection of multiple options\n\t\t *\n\t\t * This prop automatically sets the internal `closeOnSelect` prop to\n\t\t * its boolean opposite\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#multiple\n\t\t */\n\t\tmultiple: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: true,\n\t\t},\n\n\t\t/**\n\t\t * Callback to filter available options\n\t\t */\n\t\toptionsFilter: {\n\t\t\ttype: Function,\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Enable passing of `value` prop and emitted `input` events as-is\n\t\t * i.e. for usage with `v-model`\n\t\t *\n\t\t * If `true`, custom internal `value` and `input` handling is disabled\n\t\t */\n\t\tpassthru: {\n\t\t\ttype: Boolean,\n\t\t\tdefault: false,\n\t\t},\n\n\t\t/**\n\t\t * Placeholder text\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html#placeholder\n\t\t */\n\t\tplaceholder: {\n\t\t\ttype: String,\n\t\t\tdefault: t('Select a tag'),\n\t\t},\n\n\t\t/**\n\t\t * Currently selected value\n\t\t */\n\t\tvalue: {\n\t\t\ttype: [Number, Array],\n\t\t\tdefault: null,\n\t\t},\n\n\t\t/**\n\t\t * Any available prop\n\t\t *\n\t\t * @see https://vue-select.org/api/props.html\n\t\t */\n\t\t// Not an actual prop but needed to show in vue-styleguidist docs\n\t\t// eslint-disable-next-line\n\t\t' ': {},\n\t},\n\n\temits: [\n\t\t'input',\n\t\t/**\n\t\t * All events from https://vue-select.org/api/events.html\n\t\t */\n\t\t// Not an actual event but needed to show in vue-styleguidist docs\n\t\t' ',\n\t],\n\n\tdata() {\n\t\treturn {\n\t\t\tsearch: '',\n\t\t\tavailableTags: [],\n\t\t}\n\t},\n\n\tcomputed: {\n\t\tavailableOptions() {\n\t\t\tif (this.optionsFilter) {\n\t\t\t\treturn this.tags.filter(this.optionsFilter)\n\t\t\t}\n\t\t\treturn this.tags\n\t\t},\n\n\t\tlocalValue() {\n\t\t\tif (this.tags.length === 0) {\n\t\t\t\treturn []\n\t\t\t}\n\t\t\tif (this.multiple) {\n\t\t\t\treturn this.value\n\t\t\t\t\t.filter(tag => tag !== '')\n\t\t\t\t\t.map(id => this.tags.find(tag2 => tag2.id === id))\n\t\t\t} else {\n\t\t\t\treturn this.tags.find(tag => tag.id === this.value)\n\t\t\t}\n\t\t},\n\n\t\tpropsToForward() {\n\t\t\tconst {\n\t\t\t\t// Props handled by this component\n\t\t\t\tfetchTags,\n\t\t\t\toptionsFilter,\n\t\t\t\tpassthru,\n\t\t\t\t// Props to forward\n\t\t\t\t...propsToForward\n\t\t\t} = this.$props\n\n\t\t\treturn propsToForward\n\t\t},\n\n\t\ttags() {\n\t\t\tif (!this.fetchTags) {\n\t\t\t\treturn this.options\n\t\t\t}\n\t\t\treturn this.availableTags\n\t\t},\n\t},\n\n\tasync created() {\n\t\tif (!this.fetchTags) {\n\t\t\treturn\n\t\t}\n\t\ttry {\n\t\t\tconst result = await searchTags()\n\t\t\tthis.availableTags = result\n\t\t} catch (error) {\n\t\t\tconsole.error('Loading systemtags failed', error)\n\t\t}\n\t},\n\n\tmethods: {\n\t\thandleInput(value) {\n\t\t\tif (this.multiple) {\n\t\t\t\t/**\n\t\t\t\t * Emitted on input events of the multiselect field\n\t\t\t\t *\n\t\t\t\t * @type {number|number[]}\n\t\t\t\t */\n\t\t\t\tthis.$emit('input', value.map(element => element.id))\n\t\t\t} else {\n\t\t\t\tif (value === null) {\n\t\t\t\t\tthis.$emit('input', null)\n\t\t\t\t} else {\n\t\t\t\t\tthis.$emit('input', value.id)\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t},\n}\n</script>\n"],"names":["xmlToJson","xml","obj","j","attribute","i","item","nodeName","old","parseXml","dom","e","xmlToTagList","list","result","index","tag","searchTags","axios","generateRemoteUrl","_sfc_main","NcEllipsisedOption","NcSelect","option","displayName","userVisible","userAssignable","t","id","tag2","fetchTags","optionsFilter","passthru","propsToForward","error","value","element"],"mappings":"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"}