Skip to content

Commit

Permalink
work for #8129 Popup submenu
Browse files Browse the repository at this point in the history
  • Loading branch information
OlgaLarina committed Apr 22, 2024
1 parent 5d2d220 commit 03d9f00
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 21 deletions.
63 changes: 44 additions & 19 deletions src/actions/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ export interface IAction {
ariaExpanded?: boolean;
ariaRole?: string;
elementId?: string;
items?: Array<IAction>;
}

export interface IActionDropdownPopupOptions extends IListModel, IPopupOptionsBase {
Expand All @@ -161,24 +162,15 @@ export function createDropdownActionModel(actionOptions: IAction, dropdownOption
return createDropdownActionModelAdvanced(actionOptions, dropdownOptions, dropdownOptions, locOwner);
}
export function createDropdownActionModelAdvanced(actionOptions: IAction, listOptions: IListModel, popupOptions?: IPopupOptionsBase, locOwner?: ILocalizableOwner): Action {
const listModel: ListModel = new ListModel(
listOptions.items,
(item: Action) => {
if (newAction.hasTitle) {
newAction.title = item.title;
}
listOptions.onSelectionChanged(item);
innerPopupModel.toggleVisibility();
},
listOptions.allowSelection,
listOptions.selectedItem,
listOptions.onFilterStringChangedCallback
);
const oldSelectionChanged = listOptions.onSelectionChanged;
listOptions.onSelectionChanged = (item: Action, ...params: any[]) => {
if (newAction.hasTitle) { newAction.title = item.title; }
oldSelectionChanged(item, params);
};

const { innerPopupModel, listModel }: { innerPopupModel: PopupModel<any>, listModel: ListModel<Action> } =
createPopupModelWithListModel(listOptions, popupOptions);
listModel.locOwner = locOwner;
const innerPopupModel: PopupModel = new PopupModel("sv-list", { model: listModel }, popupOptions?.verticalPosition, popupOptions?.horizontalPosition, popupOptions?.showPointer, popupOptions?.isModal, popupOptions?.onCancel, popupOptions?.onApply, popupOptions?.onHide, popupOptions?.onShow, popupOptions?.cssClass, popupOptions?.title, () => {
listModel.dispose();
});
innerPopupModel.displayMode = popupOptions?.displayMode as any;

const newActionOptions = Object.assign({}, actionOptions, {
component: "sv-action-bar-item-dropdown",
Expand All @@ -196,13 +188,32 @@ export function createDropdownActionModelAdvanced(actionOptions: IAction, listOp
return newAction;
}

export function createPopupModelWithListModel(listOptions: IListModel, popupOptions: IPopupOptionsBase) {
const listModel: ListModel = new ListModel(
listOptions.items,
(item: Action) => {
listOptions.onSelectionChanged(item);
innerPopupModel.toggleVisibility();
},
listOptions.allowSelection,
listOptions.selectedItem,
listOptions.onFilterStringChangedCallback
);
const innerPopupModel: PopupModel = new PopupModel("sv-list", { model: listModel }, popupOptions?.verticalPosition, popupOptions?.horizontalPosition, popupOptions?.showPointer, popupOptions?.isModal, popupOptions?.onCancel, popupOptions?.onApply, popupOptions?.onHide, popupOptions?.onShow, popupOptions?.cssClass, popupOptions?.title, () => {
listModel.dispose();
});
innerPopupModel.displayMode = popupOptions?.displayMode as any;
return { innerPopupModel, listModel };
}

export function getActionDropdownButtonTarget(container: HTMLElement): HTMLElement {
return container?.previousElementSibling as HTMLElement;
}

export abstract class BaseAction extends Base implements IAction {
items?: IAction[];
private static renderedId = 1;
private static getNextRendredId(): number { return BaseAction.renderedId ++; }
private static getNextRendredId(): number { return BaseAction.renderedId++; }
private cssClassesValue: any;
private rendredIdValue = BaseAction.getNextRendredId();
private ownerValue: ILocalizableOwner;
Expand Down Expand Up @@ -366,6 +377,16 @@ export class Action extends BaseAction implements IAction, ILocalizableOwner {
private createLocTitle(): LocalizableString {
return this.createLocalizableString("title", this, true);
}
public setItems(items: Array<IAction>) {
this.component = "sv-list-item-group";
const { innerPopupModel, listModel }: { innerPopupModel: PopupModel<any>, listModel: ListModel<Action> } =
createPopupModelWithListModel(
{ items: items, onSelectionChanged: (item: Action, ...params: any[]) => { !!this.action && this.action(); } },
{ verticalPosition: "bottom", horizontalPosition: "left" });
innerPopupModel.cssClass = "sv-popup-inner";
this.popupModel = innerPopupModel;
}

location?: string;
@property() id: string;
@property({
Expand All @@ -381,7 +402,11 @@ export class Action extends BaseAction implements IAction, ILocalizableOwner {
@property() private _enabled: boolean;
@property() action: (context?: any, isUserAction?: boolean) => void;
@property() _component: string;
@property() items: any;
@property({
onSet: (val, target) => {
target.setItems(val);
}
}) items: any;
@property({
onSet: (val, target) => {
if (target.locTitleValue.text === val) return;
Expand Down
2 changes: 1 addition & 1 deletion src/common-styles/sv-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@

.sv-list__item:hover,
.sv-list__item:focus {
.sv-list__item-body {
& > .sv-list__item-body {
background-color: $background-dark;
}

Expand Down
4 changes: 4 additions & 0 deletions src/common-styles/sv-popup.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ sv-popup {
height: 100vh;
}

.sv-popup.sv-popup-inner {
height: 0;
}

.sv-dropdown-popup {
height: 0;
}
Expand Down
8 changes: 8 additions & 0 deletions src/knockout/components/list/list-item-group.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div data-bind="attr: { disabled: $data.item.enabled !== undefined && !ko.unwrap($data.item.enabled), title: $data.item.tooltip || $data.item.title, 'role': $data.item.ariaRole }">
<!-- ko if: $data.item.iconName -->
<!-- ko component: { name: "sv-svg-icon", params: { iconName: $data.item.iconName, size: $data.item.iconSize, css: $data.item.model.cssClasses.itemIcon } }-->
<!-- /ko -->
<!-- /ko -->
<!-- ko template: { name: 'survey-string', data: $data.item.locTitle } --><!-- /ko -->
</div>
<sv-popup params="{ model: $data.item.popupModel, getTarget: $parent.getTarget }"></sv-popup>
24 changes: 24 additions & 0 deletions src/knockout/components/list/list-item-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as ko from "knockout";
import { ImplementorBase } from "../../kobase";

const template = require("./list-item-group.html");

export let ListItemGroupViewComponent: any;

ko.components.register("sv-list-item-group", {
viewModel: {
createViewModel: (params: any) => {
new ImplementorBase(params.item);
return {
item: params.item,
model: params.model,
disableTabStop: params.item.disableTabStop,
itemClick: (data: any, event: any) => {
data.model.onItemClick(data.item);
event.stopPropagation();
}
};
},
},
template: template,
});
2 changes: 1 addition & 1 deletion src/knockout/components/list/list-item.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

<li role="option"
data-bind="css: $data.model.getItemClass($data.item), attr: { id: $data.item.elementId, 'aria-selected': $data.model.isItemSelected($data.item) ? 'true' : 'false' }, click: itemClick, key2click, visible: $data.model.isItemVisible($data.item), event: { pointerdown: function (model, event) { $data.model.onPointerDown(event, $data.item); } }"> <!-- ko if: $data.item.needSeparator -->
data-bind="css: $data.model.getItemClass($data.item), attr: { id: $data.item.elementId, 'aria-selected': $data.model.isItemSelected($data.item) ? 'true' : 'false' }, click: itemClick, key2click, visible: $data.model.isItemVisible($data.item), event: { pointerdown: function (model, event) { $data.model.onPointerDown(event, $data.item); }, mouseover: function(m, e) { $data.hover(e, $data); return true; } }"> <!-- ko if: $data.item.needSeparator -->
<div data-bind="css: $data.model.cssClasses.itemSeparator"></div>
<!-- /ko -->
<div data-bind="style: { paddingInlineStart: $data.model.getItemIndent($data.item) }, css: $data.model.cssClasses.itemBody, attr: { title: $data.item.locTitle.calculatedText }">
Expand Down
5 changes: 5 additions & 0 deletions src/knockout/components/list/list-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ ko.components.register("sv-list-item", {
itemClick: (data: any, event: any) => {
data.model.onItemClick(data.item);
event.stopPropagation();
},
hover: (event: MouseEvent, data: any) => {
if (event.type === "mouseover") {
data.model.onItemHover(data.item);
}
}
};
},
Expand Down
1 change: 1 addition & 0 deletions src/knockout/components/list/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ActionContainerImplementor } from "../action-bar/action-bar";
const template = require("./list.html");

export * from "./list-item";
export * from "./list-item-group";

export var ListViewComponent: any;

Expand Down
13 changes: 13 additions & 0 deletions src/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,19 @@ export class ListModel<T extends BaseAction = Action> extends ActionContainer<T>
}
};

public onItemHover = (itemValue: T): void => {
this.actions.forEach(action => {
if (action === itemValue && !!itemValue.popupModel) {
itemValue.popupModel.isVisible = true;
// itemValue.popupModel.isFocusedContent = !isUserAction || listModel.showFilter;
// itemValue.popupModel.toggleVisibility();
// listModel.scrollToSelectedItem();
} else if (!!action.popupModel && action.popupModel.isVisible) {
action.popupModel.isVisible = false;
}
});
}

public isItemDisabled: (itemValue: T) => boolean = (itemValue: T) => {
return itemValue.enabled !== undefined && !itemValue.enabled;
};
Expand Down

0 comments on commit 03d9f00

Please sign in to comment.