mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Forms Improvements
Summary: - Forms now have a reset button. - Choice and Reference fields in forms now have an improved select menu. - Formula and attachments column types are no longer mappable or visible in forms. - Fields in a form widget are now removed if their column is deleted. - The preview button in a published form widget has been replaced with a view button. It now opens the published form in a new tab. - A new share menu for published form widgets, with options to copy a link or embed code. - Forms can now have multiple sections. - Form widgets now indicate when publishing is unavailable (e.g. in forks or unsaved documents). - General improvements to form styling. Test Plan: Browser tests. Reviewers: jarek Reviewed By: jarek Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D4203
This commit is contained in:
@@ -15,7 +15,6 @@ import split = require("lodash/split");
|
||||
|
||||
export interface ACItem {
|
||||
// This should be a trimmed lowercase version of the item's text. It may be an accessor.
|
||||
// Note that items with empty cleanText are never suggested.
|
||||
cleanText: string;
|
||||
}
|
||||
|
||||
@@ -65,6 +64,19 @@ interface Word {
|
||||
pos: number; // Position of the word within the item where it occurred.
|
||||
}
|
||||
|
||||
export interface ACIndexOptions {
|
||||
/** The max number of items to suggest. Defaults to 50. */
|
||||
maxResults?: number;
|
||||
/**
|
||||
* Suggested matches in the same relative order as items, rather than by score.
|
||||
*
|
||||
* Defaults to false.
|
||||
*/
|
||||
keepOrder?: boolean;
|
||||
/** Show items with an empty `cleanText`. Defaults to false. */
|
||||
showEmptyItems?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a search index. It doesn't currently support updates; when any values change, the
|
||||
* index needs to be rebuilt from scratch.
|
||||
@@ -75,11 +87,12 @@ export class ACIndexImpl<Item extends ACItem> implements ACIndex<Item> {
|
||||
// All words from _allItems, sorted.
|
||||
private _words: Word[];
|
||||
|
||||
private _maxResults = this._options.maxResults ?? 50;
|
||||
private _keepOrder = this._options.keepOrder ?? false;
|
||||
private _showEmptyItems = this._options.showEmptyItems ?? false;
|
||||
|
||||
// Creates an index for the given list of items.
|
||||
// The max number of items to suggest may be set using _maxResults (default is 50).
|
||||
// If _keepOrder is true, best matches will be suggested in the order they occur in items,
|
||||
// rather than order by best score.
|
||||
constructor(items: Item[], private _maxResults: number = 50, private _keepOrder = false) {
|
||||
constructor(items: Item[], private _options: ACIndexOptions = {}) {
|
||||
this._allItems = items.slice(0);
|
||||
|
||||
// Collects [word, occurrence, position] tuples for all words in _allItems.
|
||||
@@ -132,7 +145,9 @@ export class ACIndexImpl<Item extends ACItem> implements ACIndex<Item> {
|
||||
|
||||
// Append enough non-matching indices to reach maxResults.
|
||||
for (let i = 0; i < this._allItems.length && itemIndices.length < this._maxResults; i++) {
|
||||
if (this._allItems[i].cleanText && !myMatches.has(i)) {
|
||||
if (myMatches.has(i)) { continue; }
|
||||
|
||||
if (this._allItems[i].cleanText || this._showEmptyItems) {
|
||||
itemIndices.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ export type { IOption, IOptionFull } from 'popweasel';
|
||||
export { getOptionFull } from 'popweasel';
|
||||
|
||||
export interface ISimpleListOpt<T, U extends IOption<T> = IOption<T>> {
|
||||
matchTriggerElemWidth?: boolean;
|
||||
headerDom?(): DomArg<HTMLElement>;
|
||||
renderItem?(item: U): DomArg<HTMLElement>;
|
||||
}
|
||||
@@ -42,6 +43,14 @@ export class SimpleList<T, U extends IOption<T> = IOption<T>> extends Disposable
|
||||
const renderItem = opt.renderItem || ((item: U) => getOptionFull(item).label);
|
||||
this.content = cssMenuWrap(
|
||||
dom('div',
|
||||
elem => {
|
||||
if (opt.matchTriggerElemWidth) {
|
||||
const style = elem.style;
|
||||
style.minWidth = _ctl.getTriggerElem().getBoundingClientRect().width + 'px';
|
||||
style.marginLeft = '0px';
|
||||
style.marginRight = '0px';
|
||||
}
|
||||
},
|
||||
{class: menuCssClass + ' grist-floating-menu'},
|
||||
cssMenu.cls(''),
|
||||
cssMenuExt.cls(''),
|
||||
@@ -113,7 +122,7 @@ export class SimpleList<T, U extends IOption<T> = IOption<T>> extends Disposable
|
||||
private _doAction(value: T | null) {
|
||||
// If value is null, simply close the menu. This happens when pressing enter with no element
|
||||
// selected.
|
||||
if (value) { this._action(value); }
|
||||
if (value !== null) { this._action(value); }
|
||||
this._ctl.close();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user