Skip to content

Commit

Permalink
Issue/4895-Add-an-option-to-expand-and-collapse-panels-on-a-design-su…
Browse files Browse the repository at this point in the history
…rface (#5631)

* #4895 Add an option to expand and collapse panels on a design surface
Fixes #4895

* #4895 - fixed buttons

* #4895 panel and question expand/collapse
Fixes #4895

* #4895 - saving expanded collapsed state

* #4895 - all platforms and v-test

* #4895 - styles, tests

* #4895 do not grow collapsed questions in row
Fixes #4895

* #4895 fix knockout focus
Fixes #4895

* #4895 - add option

* Rename the property and add a description draft

* fixed unit and knockout v-tests

* #4895 - rename property

* #4895 - fixed markup

* #4895 - fix f-test

* #4895 - update screenshots

* #4895 - fix f-test

* #4895 - fix f-test

* #4895 - fixed v-test

---------

Co-authored-by: Aleksey Novikov <[email protected]>
Co-authored-by: RomanTsukanov <[email protected]>
  • Loading branch information
3 people authored Jul 9, 2024
1 parent 2d758bd commit 590f295
Show file tree
Hide file tree
Showing 29 changed files with 454 additions and 11 deletions.
3 changes: 3 additions & 0 deletions packages/survey-creator-angular/src/panel.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
(pointerdown)="adorner.onPointerDown($event)">
<svg class="svc-question__drag-element" [iconName]="'icon-drag-area-indicator_24x16'" [size]="24"
sv-ng-svg-icon></svg>
<div class="svc-question__top-actions">
<sv-action-bar [model]="adorner.topActionContainer" [handleClick]="false"></sv-action-bar>
</div>
</div>

<ng-template [component]="{ name: componentName, data: componentData }"></ng-template>
Expand Down
3 changes: 3 additions & 0 deletions packages/survey-creator-angular/src/question.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
<div *ngIf="adorner.allowDragging" class="svc-question__drag-area" (pointerdown)="adorner.onPointerDown($event)">
<svg class="svc-question__drag-element" [iconName]="'icon-drag-area-indicator_24x16'" [size]="24"
sv-ng-svg-icon></svg>
<div class="svc-question__top-actions">
<sv-action-bar [model]="adorner.topActionContainer" [handleClick]="false"></sv-action-bar>
</div>
</div>

<ng-template [component]="{ name: componentName, data: componentData }"></ng-template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ import {
SurveyElement,
property,
actionModeType,
IAction
IAction,
ActionContainer,
ComputedUpdater
} from "survey-core";
import { SurveyCreatorModel } from "../creator-base";
import { settings } from "../creator-settings";
import { DesignerStateManager } from "./tabs/designer-state-manager";
import { TabDesignerPlugin } from "./tabs/designer-plugin";

export class SurveyElementActionContainer extends AdaptiveActionContainer {
private needToShrink(item: Action, shrinkStart: boolean, shrinkEnd: boolean) {
Expand Down Expand Up @@ -86,7 +90,16 @@ export class SurveyElementActionContainer extends AdaptiveActionContainer {

export class SurveyElementAdornerBase<T extends SurveyElement = SurveyElement> extends Base {
public actionContainer: SurveyElementActionContainer;
public topActionContainer: ActionContainer;
protected designerStateManager: DesignerStateManager;
@property({ defaultValue: true }) allowDragging: boolean;
@property({
onSet: (val, target: SurveyElementAdornerBase<T>) => {
target.renderedCollapsed = val;
if (target.designerStateManager && target.surveyElement) target.designerStateManager.getElementState(target.surveyElement).collapsed = val;
}
}) collapsed: boolean;
@property() renderedCollapsed: boolean;
private allowEditOption: boolean;
private selectedPropPageFunc: (sender: Base, options: any) => void;
private sidebarFlyoutModeChangedFunc: (sender: Base, options: any) => void;
Expand All @@ -96,6 +109,8 @@ export class SurveyElementAdornerBase<T extends SurveyElement = SurveyElement> e
protected surveyElement: T
) {
super();
this.designerStateManager = (creator.getPlugin("designer") as TabDesignerPlugin)?.designerStateManager;
this.designerStateManager?.initForElement(surveyElement);
this.selectedPropPageFunc = (sender: Base, options: any) => {
if (options.name === "isSelectedInDesigner") {
this.onElementSelectedChanged(options.newValue);
Expand All @@ -109,6 +124,18 @@ export class SurveyElementAdornerBase<T extends SurveyElement = SurveyElement> e
this.actionContainer = new SurveyElementActionContainer();
this.actionContainer.dotsItem.iconSize = 16;
this.actionContainer.dotsItem.popupModel.horizontalPosition = "center";

this.topActionContainer = new ActionContainer();
this.topActionContainer.sizeMode = "small";
this.topActionContainer.setItems([{
id: "collapse",
iconName: new ComputedUpdater<string>(() => this.collapsed ? "icon-restore_16x16" : "icon-collapse-detail-light_16x16") as any,
iconSize: 16,
action: () => {
this.collapsed = !this.collapsed;
}
}]);
this.collapsed = !!surveyElement && (this.designerStateManager?.getElementState(surveyElement).collapsed);
this.setSurveyElement(surveyElement);
this.creator.sidebar.onPropertyChanged.add(this.sidebarFlyoutModeChangedFunc);
this.setShowAddQuestionButton(true);
Expand Down
89 changes: 85 additions & 4 deletions packages/survey-creator-core/src/components/question.scss
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ svc-question {
}
}

.svc-question__content>div {
.svc-question__content>div,
.svc-question__placeholders>div {
overflow: visible;
}

Expand Down Expand Up @@ -451,21 +452,73 @@ svc-question,

// EO reset styles for drag-drop-ghost-survey-element to avoid layout jumping while dragging

.svc-hovered>.svc-question__content>.svc-question__drag-area {
.svc-hovered>.svc-question__content>.svc-question__drag-area>.svc-question__drag-element {
visibility: visible;
}

.svc-question__content.svc-question__content--selected>.svc-question__drag-area {
.svc-question__content.svc-question__content--selected>.svc-question__drag-area>.svc-question__drag-element {
visibility: visible;
z-index: 1;
}

.svc-question__adorner--collapsed {
.svc-question__content {
&>* {
display: none
}
.svc-question__drag-area {
display: flex,
}
.sd-element {
display: block;
&>*:not(.sd-element__header ) {
display: none
}
.sd-element__header
{
&>*:not(.sd-element__title) {
display: none;
}
.sd-element__title,
.sd-title.sd-element__title.sd-element__title--hidden {
display: block;
}
}
}
}
}

.svc-question__adorner--collapsed {
.svc-question__content {
flex-grow: 0;
padding-bottom: calcSize(4);
.sd-element__header,
.sd-element--complex > .sd-element__header {
padding-top: 0;
padding-bottom: 0;
}
}
}
.svc-creator--mobile {
.svc-question__top-actions {
padding: 0;
}
.svc-question__adorner--collapsed {
.svc-question__content {
padding-bottom: calcSize(2);
}
.svc-question__content--selected {
padding-bottom: calcSize(3);
}
}
}


.svc-question__drag-area {
position: absolute;
cursor: move;
top: 0;
left: 0;
visibility: hidden;
height: calcSize(3.5);
width: 100%;
display: flex;
Expand All @@ -477,6 +530,7 @@ svc-question,
width: 100%;
height: calcSize(4);
opacity: 0.5;
visibility: hidden;

use {
fill: $foreground-light;
Expand Down Expand Up @@ -863,4 +917,31 @@ svc-question,
}
}
}
}

.svc-question__top-actions {
padding: calcSize(0.5);
position: absolute;
top: 0;
right: 0;
visibility: hidden;
.sv-action-bar-item {
use {
fill: $foreground-dim-light;
}
margin: 0;
padding: calcSize(0.5);
opacity: 0.5;
height: 24px;
&:hover, &:focus {
opacity: initial;
}
}
}

.svc-question__adorner--collapse-onhover.svc-hovered,
.svc-question__adorner--collapse-always {
.svc-question__top-actions {
visibility: visible;
}
}
7 changes: 6 additions & 1 deletion packages/survey-creator-core/src/components/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface QuestionBannerParams {
export class QuestionAdornerViewModel extends SurveyElementAdornerBase {
@property() isDragged: boolean;
@property({ defaultValue: "" }) currentAddQuestionType: string;

placeholderComponent: string;
placeholderComponentData: any;

Expand Down Expand Up @@ -98,7 +99,11 @@ export class QuestionAdornerViewModel extends SurveyElementAdornerBase {
}

rootCss() {
return this.surveyElement.isQuestion && !(<Question>this.surveyElement).startWithNewLine ? " svc-question__adorner--start-with-new-line" : "";
const isStartWithNewLine = this.surveyElement.isQuestion && !(<Question>this.surveyElement).startWithNewLine;
return new CssClassBuilder()
.append("svc-question__adorner--start-with-new-line", isStartWithNewLine)
.append("svc-question__adorner--collapse-" + this.creator.expandCollapseButtonVisibility, true)
.append("svc-question__adorner--collapsed", !!this.renderedCollapsed).toString();
}

css() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { PropertyGridModel } from "../../property-grid";
import { PropertyGridViewModel } from "../../property-grid/property-grid-view-model";
import { SidebarTabModel } from "../side-bar/side-bar-tab-model";
import { TabDesignerViewModel } from "./designer";
import { DesignerStateManager } from "./designer-state-manager";

export class TabDesignerPlugin implements ICreatorPlugin {
public model: TabDesignerViewModel;
Expand All @@ -16,6 +17,7 @@ export class TabDesignerPlugin implements ICreatorPlugin {
private saveSurveyAction: Action;
public previewAction: Action;
private designerAction: Action;
public designerStateManager: DesignerStateManager;

private get isSurveySelected(): boolean {
return this.creator.isElementSelected(<any>this.creator.survey);
Expand Down Expand Up @@ -48,6 +50,13 @@ export class TabDesignerPlugin implements ICreatorPlugin {
return result;
});
this.toolboxTab = this.creator.sidebar.addTab("toolbox", "svc-toolbox", creator);
this.designerStateManager = new DesignerStateManager();
this.designerStateManager.initForSurvey(this.creator.survey);
this.creator.onSurveyInstanceCreated.add((s, o) => {
if (o.reason == "designer") {
this.designerStateManager.initForSurvey(o.survey);
}
});
this.creator.onPropertyChanged.add((sender, options) => {
if (options.name === "toolboxLocation") {
if (this.toolboxTab.visible && options.newVal !== "sidebar") {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { SurveyElement, SurveyModel } from "survey-core";
class ElementState {
collapsed: boolean = false;
}

interface ElementStateMap {
[key: string]: ElementState;
}

export class DesignerStateManager {
private elementState: ElementStateMap = {};
private pageState: ElementStateMap = {};
private getStateMapForElement(element: SurveyElement) {
return (element && element.isPage) ? this.pageState : this.elementState;
}

private onQuestionAddedHandler = (sender, opts): void => {
this.elementState[opts.question.name] = new ElementState();
}
private onPageAddedHandler = (sender, opts): void => {
this.pageState[opts.page.name] = new ElementState();
}
private onPanelAddedHandler = (sender, opts): void => {
this.elementState[opts.panel.name] = new ElementState();
}
initForSurvey(survey: SurveyModel) {
survey.onQuestionAdded.add(this.onQuestionAddedHandler);
survey.onPageAdded.add(this.onPageAddedHandler);
survey.onPanelAdded.add(this.onPanelAddedHandler);
}
initForElement(element: SurveyElement): void {
if (!element) return;
const stateMap = this.getStateMapForElement(element);
element.registerFunctionOnPropertyValueChanged(
"name",
(newName) => {
delete stateMap[element.name];
stateMap[newName] = new ElementState();
},
"designerStateManager"
);
}
getElementState(element: SurveyElement): ElementState {
const stateMap = this.getStateMapForElement(element);
const name = element.name;
let state = stateMap[name];
if (state) return state;
state = new ElementState();
stateMap[name] = new ElementState();
return state;
}
constructor() {
}
}
12 changes: 12 additions & 0 deletions packages/survey-creator-core/src/creator-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3624,6 +3624,18 @@ export class SurveyCreatorModel extends Base
* @see toolboxLocation
*/
@property({ defaultValue: "right" }) sidebarLocation: "left" | "right";

/*
* Specifies the visibility of the buttons that expand and collapse survey elements on the design surface.
*
* Possible values:
*
* - `"onhover"` (default) - Displays an expand/collapse button when a survey element is hovered over or selected.
* - `"always"` - Displays the expand/collapse buttons permanently.
* - `"never"` - Hides the expand/collapse buttons.
*/
@property({ defaultValue: "never" }) expandCollapseButtonVisibility?: "never" | "onhover" | "always";

selectFromStringEditor: boolean;

@property({
Expand Down
5 changes: 5 additions & 0 deletions packages/survey-creator-core/src/images/collapse-v_16x16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions packages/survey-creator-core/src/images/expand-v_16x16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/survey-creator-core/src/images/restore_16x16.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion packages/survey-creator-core/src/responsivity.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
}
}
}

.svc-question__drag-area {
height: calcSize(3);
}
.svc-question__content--selected {
.svc-rating-question-controls {
bottom: calcSize(10);
Expand Down
Loading

0 comments on commit 590f295

Please sign in to comment.