diff --git a/README.md b/README.md index 15317404d..60d8f28a5 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,6 @@ But to resemble the CSS syntax, new patterns should instead separate each word w - [pat-preventdoublesubmit](src/pat/preventdoublesubmit/README.md): Prevent multiple submissions of the same forn. - [pat-querystring](src/pat/querystring/README.md): Show the querystring selection app. - [pat-recurrence](src/pat/recurrence/README.md): Show the recurrence widget. -- [pat-relateditems](src/pat/relateditems/README.md): Show a widget to select related items. (deprecated: use `pat-contentbrowser` instead) - [pat-select2](src/pat/select2/README.md): Show a widget which enhances dropdown selections with automatic suggestions, search and tagging functionality. - [pat-sortable](src/pat/sortable/README.md): A pattern to make listings sortable. - [pat-structure](src/pat/structure/README.md): Plone's folder contents app. @@ -111,6 +110,7 @@ But to resemble the CSS syntax, new patterns should instead separate each word w Deprecated patterns: +- [pat-relateditems](src/pat/relateditems/README.md) (_deprecated_): Show a widget to select related items. (use `pat-contentbrowser` instead) - [pat-backdrop](src/pat/backdrop/README.md) (_deprecated_): Renders a dark background. - [pat-contentloader](src/pat/contentloader/README.md) (_deprecated_): Load remote or local content into a target. - [pat-texteditor](src/pat/texteditor/README.md) (_deprecated_): Show a code editor. diff --git a/src/pat/contentbrowser/contentbrowser.js b/src/pat/contentbrowser/contentbrowser.js index 0954fe867..60c7e3846 100644 --- a/src/pat/contentbrowser/contentbrowser.js +++ b/src/pat/contentbrowser/contentbrowser.js @@ -22,6 +22,7 @@ parser.addArgument( "review_state", ], null, true ); +parser.addArgument("width"); parser.addArgument("max-depth"); parser.addArgument("base-path"); parser.addArgument("context-path"); @@ -33,6 +34,7 @@ parser.addArgument("selection-template"); parser.addArgument("favorites"); parser.addArgument("recently-used"); parser.addArgument("recently-used-key"); +parser.addArgument("recently-used-max-items", 20); parser.addArgument("b-size"); class Pattern extends BasePattern { @@ -43,7 +45,7 @@ class Pattern extends BasePattern { async init() { this.el.setAttribute('style', 'display: none'); - // ensure an id on our elemen (TinyMCE doesn't have one) + // ensure an id on our element (TinyMCE doesn't have one) let nodeId = this.el.getAttribute("id"); if (!nodeId) { nodeId = utils.generateId(); diff --git a/src/pat/contentbrowser/src/App.svelte b/src/pat/contentbrowser/src/App.svelte index e90befbc5..34bc2e45e 100644 --- a/src/pat/contentbrowser/src/App.svelte +++ b/src/pat/contentbrowser/src/App.svelte @@ -14,6 +14,7 @@ } from "./stores"; export let maxDepth; + export let width; export let attributes; export let contextPath; export let vocabularyUrl; @@ -29,6 +30,7 @@ export let favorites; export let recentlyUsed; export let recentlyUsedKey; + export let recentlyUsedMaxItems; export let bSize = 20; const log = logger.getLogger("pat-contentbrowser"); @@ -58,6 +60,7 @@ attributes: attributes, contextPath: contextPath, vocabularyUrl: vocabularyUrl, + width: width, maxDepth: maxDepth, basePath: basePath, selectableTypes: selectableTypes, @@ -70,6 +73,7 @@ favorites: favorites, recentlyUsed: recentlyUsed, recentlyUsedKey: recentlyUsedKey, + recentlyUsedMaxItems: recentlyUsedMaxItems, base_url: base_url, pageSize: bSize, }; diff --git a/src/pat/contentbrowser/src/ContentBrowser.svelte b/src/pat/contentbrowser/src/ContentBrowser.svelte index f22f11412..6795f52a0 100644 --- a/src/pat/contentbrowser/src/ContentBrowser.svelte +++ b/src/pat/contentbrowser/src/ContentBrowser.svelte @@ -6,7 +6,15 @@ import _t from "../../../core/i18n-wrapper"; import Upload from "../../upload/upload"; import contentStore from "./ContentStore"; - import { clickOutside, get_items_from_uids, resolveIcon } from "./utils"; + import { + clickOutside, + get_items_from_uids, + request, + resolveIcon, + updateRecentlyUsed, + } from "./utils"; + import Favorites from "./Favorites.svelte"; + import RecentlyUsed from "./RecentlyUsed.svelte"; animateScroll.setGlobalOptions({ scrollX: true, @@ -117,7 +125,7 @@ const levelWrapper = e.currentTarget.closest(".levelItems"); const prevSelection = levelWrapper.querySelectorAll(".selectedItem"); - if (prevSelection.length) { + if (prevSelection.length && $config.maximumSelectionSize != 1) { // check for pressed shift or ctrl/meta key for multiselection if (shiftKey || e?.shiftKey) { @@ -143,7 +151,7 @@ action: select ? "add" : "remove", }); } - } else if (e?.metaKey || e?.ctrlKey) { + } else if (e?.metaKey || e?.ctrlKey) { // de/select multiple single items // NOTE: only for mouse click event updatePreview({ @@ -155,12 +163,11 @@ [...prevSelection].map((el) => el.classList.remove("selectedItem")); changePath(item, e); } - } else { changePath(item, e); } - e.currentTarget.focus(); // needed for keyboard navigation + e.currentTarget.focus(); // needed for keyboard navigation e.currentTarget.classList.add("selectedItem"); } @@ -170,10 +177,10 @@ return; } const possibleFocusEls = [ - ...document.querySelectorAll(".levelColumn .inPath"), // previously selected folder - ...document.querySelectorAll(".levelColumn .selectedItem"), // previously selected item - document.querySelector(".levelColumn .contentItem"), // default first item - ] + ...document.querySelectorAll(".levelColumn .inPath"), // previously selected folder + ...document.querySelectorAll(".levelColumn .selectedItem"), // previously selected item + document.querySelector(".levelColumn .contentItem"), // default first item + ]; if (possibleFocusEls.length) { keyboardNavInitialized = true; possibleFocusEls[0].focus(); @@ -220,14 +227,24 @@ } if (e.key == "Enter") { if (isSelectable(item)) { - addSelectedItems(item); + if ($config.maximumSelectionSize == 1) { + addItem(item); + } else { + addSelectedItems(); + } } } } async function addItem(item) { - selectedItems.update((n) => [...n, item]); - selectedUids.update(() => $selectedItems.map((x) => x.UID)); + if ($config.maximumSelectionSize == 1) { + selectedItems.set([item]); + selectedUids.set([item.UID]); + } else { + selectedItems.update((n) => [...n, item]); + selectedUids.update(() => $selectedItems.map((x) => x.UID)); + } + updateRecentlyUsed(item, $config); updatePreview({ action: "clear" }); $showContentBrowser = false; keyboardNavInitialized = false; @@ -248,6 +265,29 @@ keyboardNavInitialized = false; } + function selectRecentlyUsed(event) { + addItem(event.detail.item); + } + + async function selectFavorite(event) { + const path = event.detail.item.path; + const response = await request({ + vocabularyUrl: $config.vocabularyUrl, + attributes: $config.attributes, + levelInfoPath: path, + }); + if (!response.total) { + alert(`${path} not found!`); + return; + } + const item = response.results[0]; + if (!item.path) { + // fix for Plone Site + item.path = "/"; + } + changePath(item); + } + function cancelSelection() { $showContentBrowser = false; keyboardNavInitialized = false; @@ -325,32 +365,39 @@