Skip to content

Commit

Permalink
Merge pull request #1397 from plone/contentbrowser-rootpath-searchmode
Browse files Browse the repository at this point in the history
  • Loading branch information
petschki authored Oct 11, 2024
2 parents 87272a8 + c569cd4 commit f3c5e1a
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 82 deletions.
30 changes: 19 additions & 11 deletions src/pat/contentbrowser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@ Show a widget to select items in an offcanvas miller-column browser.

## Configuration

| Option | Type | Default | Description |
| :------------------------: | :-----: | :-------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| attributes | array | ['UID', 'Title', 'portal_type', 'path'] | This list is passed to the server during an AJAX request to specify the attributes which should be included on each item. |
| basePath | string | set to rootPath. | Start browse/search in this path. |
| contextPath | string | | Path of the object, which is currently edited. If this path is given, this object will not be selectable. |
| favorites | array | [] | Array of objects. These are favorites, which can be used to quickly jump to different locations. Objects have the attributes "title" and "path". |
| maximumSelectionSize | integer | -1 | The maximum number of items that can be selected in a multi-select control. If this number is less than 1 selection is not limited. |
| bSize | integer | 10 | Batch size to break down big result sets into multiple pages. |
| separator | string | ',' | Select2 option. String which separates multiple items. |
| upload | boolean | | Allow file and image uploads from within the related items widget. |
| vocabularyUrl | string | null | This is a URL to a JSON-formatted file used to populate the list |
| Option | Type | Default | Description |
| :------------------------: | :-----: | :-------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------: |
| vocabularyUrl | string | null | This is a URL to a JSON-formatted file used to populate the list |
| attributes | array | ['UID', 'Title', 'portal_type', 'path'] | This list is passed to the server during an AJAX request to specify the attributes which should be included on each item. |
| rootPath | string | "/" | Browsing/searching root path. You will not get beneath this path |
| rootUrl | string | | Browsing/searching root url. |
| basePath | string | set to rootPath. | Start browse/search in this path. |
| contextPath | string | | Path of the object, which is currently edited. If this path is given, this object will not be selectable. |
| favorites | array | [] | Array of objects. These are favorites, which can be used to quickly jump to different locations. Objects have the attributes "title" and "path". |
| maximumSelectionSize | integer | -1 | The maximum number of items that can be selected in a multi-select control. If this number is less than 1 selection is not limited. |
| mode | string | "browse" | Toggle between "browse" and "search" |
| width | integer | | Override the width of the selected items field |
| bSize | integer | 10 | Batch size of the items listed in levels |
| maxDepth | integer | | Maximum level depth for "browse" mode |
| separator | string | ',' | Select2 option. String which separates multiple items. |
| upload | boolean | | Allow file and image uploads from within the related items widget. |
| recentlyUsed | boolean | false | Show the recently used items dropdown. |
| recentlyUsedKey | integer | | Storage key for saving the recently used items. This is generated with fieldname and username in the patternoptions. |
| recentlyUsedMaxItems | integer | 20 | Maximum items to keep in recently used list. 0: no restriction. |


## Default
Expand Down
7 changes: 5 additions & 2 deletions src/pat/contentbrowser/contentbrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ parser.addArgument(
], null, true
);
parser.addArgument("width");
parser.addArgument("mode");
parser.addArgument("max-depth");
parser.addArgument("root-path");
parser.addArgument("root-url");
parser.addArgument("base-path");
parser.addArgument("context-path");
parser.addArgument("maximum-selection-size");
Expand All @@ -34,7 +37,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("recently-used-max-items");
parser.addArgument("b-size");

class Pattern extends BasePattern {
Expand All @@ -43,7 +46,7 @@ class Pattern extends BasePattern {
static parser = parser;

async init() {
this.el.setAttribute('style', 'display: none');
this.el.style.display = "none";

// ensure an id on our element (TinyMCE doesn't have one)
let nodeId = this.el.getAttribute("id");
Expand Down
11 changes: 6 additions & 5 deletions src/pat/contentbrowser/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
export let contextPath;
export let vocabularyUrl;
export let mode = "browse";
export let rootPath = "";
export let rootUrl = "";
export let basePath = "";
export let selectableTypes = [];
export let maximumSelectionSize = -1;
Expand Down Expand Up @@ -48,12 +50,10 @@
const currentPath = getContext("currentPath");
if (!$currentPath) {
$currentPath = basePath || "/";
// if root path is not above base path we start at rootPath
$currentPath = basePath.indexOf(rootPath) != 0 ? rootPath : basePath;
}
// base_url information
const base_url = document.body.getAttribute("data-portal-url");
let config = getContext("config");
$config = {
mode: mode,
Expand All @@ -62,6 +62,8 @@
vocabularyUrl: vocabularyUrl,
width: width,
maxDepth: maxDepth,
rootPath: rootPath,
rootUrl: rootUrl,
basePath: basePath,
selectableTypes: selectableTypes,
maximumSelectionSize: maximumSelectionSize,
Expand All @@ -74,7 +76,6 @@
recentlyUsed: recentlyUsed,
recentlyUsedKey: recentlyUsedKey,
recentlyUsedMaxItems: recentlyUsedMaxItems,
base_url: base_url,
pageSize: bSize,
};
Expand Down
42 changes: 21 additions & 21 deletions src/pat/contentbrowser/src/ContentBrowser.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
const uploadEl = document.querySelector(".upload-wrapper");
uploadEl.classList.add("pat-upload");
const patUpload = new Upload(uploadEl, {
baseUrl: $config.base_url,
baseUrl: $config.rootUrl,
currentPath: $currentPath,
relativePath: "@@fileUpload",
allowPathSelection: false,
Expand All @@ -92,21 +92,22 @@
} else {
const pathParts = item.path.split("/");
const folderPath = pathParts.slice(0, pathParts.length - 1).join("/");
currentPath.set(folderPath || "/");
currentPath.set(folderPath || $config.rootPath);
updatePreview({ data: item });
}
scrollToRight();
}
function changePath(item, e) {
// always hide upload when changing path
showUpload = false;
// clear previous selection
updatePreview({ action: "clear" });
if (item === "/") {
if (item === "/" || item === $config.rootPath) {
// clicked "home" button
currentPath.set(item);
currentPath.set($config.rootPath);
return;
}
Expand Down Expand Up @@ -179,8 +180,10 @@
const possibleFocusEls = [
...document.querySelectorAll(".levelColumn .inPath"), // previously selected folder
...document.querySelectorAll(".levelColumn .selectedItem"), // previously selected item
document.querySelector(".levelColumn .contentItem"), // default first item
];
if(!possibleFocusEls.length && document.querySelector(".levelColumn .contentItem")) {
possibleFocusEls.push(document.querySelector(".levelColumn .contentItem"));
}
if (possibleFocusEls.length) {
keyboardNavInitialized = true;
possibleFocusEls[0].focus();
Expand Down Expand Up @@ -282,8 +285,8 @@
}
const item = response.results[0];
if (!item.path) {
// fix for Plone Site
item.path = "/";
// fix for root
item.path = $config.rootPath;
}
changePath(item);
}
Expand All @@ -309,18 +312,12 @@
}
function itemInPath(item) {
return $currentPath.indexOf(item.path) != -1;
return $config.mode == "browse" && $currentPath.indexOf(item.path) != -1;
}
function filterItems() {
let timeoutId;
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => {
contentItems.get({ path: $currentPath, searchTerm: this.value });
}, 300);
}
const filterItems = utils.debounce((e) => {
contentItems.get({ path: $currentPath, searchTerm: e.target.value });
}, 300);
function loadMore(node) {
const observer = new IntersectionObserver(
Expand Down Expand Up @@ -413,13 +410,13 @@
in:fly|local={{ duration: 300 }}
>
<div class="levelToolbar">
{#if i == 0}
{#if i == 0 && $config.mode == "browse"}
<button
type="button"
class="btn btn-link btn-xs ps-0"
tabindex="0"
on:keydown={() => changePath("/")}
on:click={() => changePath("/")}
on:keydown={() => changePath($config.rootPath)}
on:click={() => changePath($config.rootPath)}
><svg
use:resolveIcon={{ iconName: "house" }}
/></button
Expand All @@ -432,7 +429,7 @@
on:click|preventDefault={() => addItem(level)}
>
{_t("select ${level_path}", {
level_path: level.absPath || "/",
level_path: level.displayPath,
})}
</button>
{/if}
Expand Down Expand Up @@ -505,6 +502,9 @@
}}
/>
{item.Title}
{#if $config.mode == "search"}
<br><span class="small">{item.path}</span>
{/if}
</div>
{/if}
{#if item.is_folderish && $config.mode == "browse"}
Expand Down
Loading

0 comments on commit f3c5e1a

Please sign in to comment.