@nextcloud/vue
Version:
Nextcloud vue components
325 lines (324 loc) • 9.26 kB
JavaScript
;
const Components_NcEllipsisedOption = require("../Components/NcEllipsisedOption.cjs");
const NcSelect = require("./NcSelect-YHwbPAJD.cjs");
const axios = require("@nextcloud/axios");
const router = require("@nextcloud/router");
const _l10n = require("./_l10n-CjO_W5Dt.cjs");
const useModelMigration = require("./useModelMigration-D5zhrNXr.cjs");
const _pluginVue2_normalizer = require("./_plugin-vue2_normalizer-V0q-tHlQ.cjs");
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
const axios__default = /* @__PURE__ */ _interopDefault(axios);
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") {
const 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) => {
const json = xmlToJson(parseXml(xml));
const list = json["d:multistatus"]["d:response"];
const result = [];
for (const index in list) {
const tag = list[index]["d:propstat"];
if (tag["d:status"]["#text"] !== "HTTP/1.1 200 OK") {
continue;
}
result.push({
id: parseInt(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 = async function() {
if (window.NextcloudVueDocs) {
return Promise.resolve(xmlToTagList(window.NextcloudVueDocs.tags));
}
const result = await axios__default.default({
method: "PROPFIND",
url: router.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>`
});
return xmlToTagList(result.data);
};
_l10n.register(_l10n.t0);
const _sfc_main = {
name: "NcSelectTags",
components: {
NcEllipsisedOption: Components_NcEllipsisedOption,
NcSelect: NcSelect.NcSelect
},
model: {
prop: "modelValue",
event: "update:modelValue"
},
props: {
// Add NcSelect prop defaults and populate $props
...NcSelect.NcSelect.props,
/**
* Enable automatic fetching of tags
*
* If `false`, available tags must be passed using the `options` prop
*/
fetchTags: {
type: Boolean,
default: true
},
/**
* Callback to generate the label text
*
* @see https://vue-select.org/api/props.html#getoptionlabel
*/
getOptionLabel: {
type: Function,
default: (option) => {
const { displayName, userVisible, userAssignable } = option;
if (userVisible === false) {
return _l10n.t("{tag} (invisible)", { tag: displayName });
}
if (userAssignable === false) {
return _l10n.t("{tag} (restricted)", { tag: displayName });
}
return displayName;
}
},
/**
* Sets the maximum number of tags to display in the dropdown list
*
* Because of compatibility reasons only 5 tag entries are shown by
* default
*/
limit: {
type: Number,
default: 5
},
/**
* Allow selection of multiple options
*
* This prop automatically sets the internal `closeOnSelect` prop to
* its boolean opposite
*
* @see https://vue-select.org/api/props.html#multiple
*/
multiple: {
type: Boolean,
default: true
},
/**
* Callback to filter available options
*/
optionsFilter: {
type: Function,
default: null
},
/**
* Enable passing of `value` prop and emitted `input` events as-is
* i.e. for usage with `v-model`
*
* If `true`, custom internal `value` and `input` handling is disabled
*/
passthru: {
type: Boolean,
default: false
},
/**
* Placeholder text
*
* @see https://vue-select.org/api/props.html#placeholder
*/
placeholder: {
type: String,
default: _l10n.t("Select a tag")
},
/**
* Removed in v9 - use `modelValue` (`v-model`) instead
* @deprecated
*/
value: {
type: [Number, Array, Object],
default: void 0
},
/**
* Currently selected value
*/
modelValue: {
type: [Number, Array, Object],
default: null
},
/**
* Any available prop
*
* @see https://vue-select.org/api/props.html
*/
// Not an actual prop but needed to show in vue-styleguidist docs
// eslint-disable-next-line
" ": {}
},
emits: [
/**
* Removed in v9 - use `update:modelValue` (`v-model`) instead
*/
"input",
/**
* Emitted on input events of the multiselect field
*
* @type {number|number[]}
*/
"update:modelValue",
/** Same as update:modelValue for Vue 2 compatibility */
"update:model-value",
/**
* All events from https://vue-select.org/api/events.html
*/
// Not an actual event but needed to show in vue-styleguidist docs
" "
],
setup() {
const model = useModelMigration.useModelMigration("value", "input");
const noop = () => {
};
return {
model,
noop
};
},
data() {
return {
search: "",
availableTags: []
};
},
computed: {
availableOptions() {
if (this.optionsFilter) {
return this.tags.filter(this.optionsFilter);
}
return this.tags;
},
localValue() {
if (this.tags.length === 0) {
return [];
}
if (this.multiple) {
return this.model.filter((tag) => tag !== "").map((id) => this.tags.find((tag2) => tag2.id === id));
} else {
return this.tags.find((tag) => tag.id === this.model);
}
},
propsToForward() {
const {
// Props handled by this component
fetchTags,
optionsFilter,
passthru,
// Props to forward
...propsToForward
} = this.$props;
return propsToForward;
},
tags() {
if (!this.fetchTags) {
return this.options;
}
return this.availableTags;
}
},
async created() {
if (!this.fetchTags) {
return;
}
try {
const result = await searchTags();
this.availableTags = result;
} catch (error) {
console.error("Loading systemtags failed", error);
}
},
methods: {
handleInput(value) {
if (this.multiple) {
this.model = value.map((element) => element.id);
} else {
if (value === null) {
this.model = null;
} else {
this.model = value.id;
}
}
}
}
};
var _sfc_render = function render() {
var _vm = this, _c = _vm._self._c;
return _c("NcSelect", _vm._g(_vm._b({ attrs: { "options": _vm.availableOptions, "close-on-select": !_vm.multiple, "value": _vm.passthru ? _vm.model : _vm.localValue }, on: { "search": (searchString) => _vm.search = searchString }, scopedSlots: _vm._u([{ key: "option", fn: function(option) {
return [_c("NcEllipsisedOption", { attrs: { "name": _vm.getOptionLabel(option), "search": _vm.search } })];
} }, { key: "selected-option", fn: function(selectedOption) {
return [_c("NcEllipsisedOption", { attrs: { "name": _vm.getOptionLabel(selectedOption), "search": _vm.search } })];
} }, _vm._l(_vm.$scopedSlots, function(_, name) {
return { key: name, fn: function(data) {
return [_vm._t(name, null, null, data)];
} };
})], null, true) }, "NcSelect", _vm.propsToForward, false), {
..._vm.$listeners,
input: _vm.passthru ? _vm.$listeners.input : _vm.noop,
"update:modelValue": _vm.passthru ? _vm.$listeners["update:modelValue"] : _vm.handleInput,
"update:model-value": _vm.passthru ? _vm.$listeners["update:model-value"] : _vm.noop
}));
};
var _sfc_staticRenderFns = [];
var __component__ = /* @__PURE__ */ _pluginVue2_normalizer.normalizeComponent(
_sfc_main,
_sfc_render,
_sfc_staticRenderFns,
false,
null,
null
);
const NcSelectTags = __component__.exports;
exports.NcSelectTags = NcSelectTags;