diff --git a/src/component/container/element-list.tsx b/src/component/container/element-list.tsx index fc11b9b61..db1e65050 100644 --- a/src/component/container/element-list.tsx +++ b/src/component/container/element-list.tsx @@ -1,5 +1,5 @@ import { elementMenu } from '../../electron/context-menus'; -import { ElementCommand } from '../../store/command/element-command'; +import { ElementLocationCommand } from '../../store/command/element-location-command'; import { ElementWrapper } from './element-wrapper'; import { ListItemProps } from '../../lsg/patterns/list'; import { createMenu } from '../../electron/menu'; @@ -55,7 +55,7 @@ export class ElementList extends React.Component { return { label: key, - value: pattern.getName(), + value: element.getName(), onClick: updatePageElement, onContextMenu: () => elementMenu(element), handleDragStart: (e: React.DragEvent) => { @@ -97,7 +97,7 @@ export class ElementList extends React.Component { } } - store.execute(ElementCommand.addChild(newParent, draggedElement, newIndex)); + store.execute(ElementLocationCommand.addChild(newParent, draggedElement, newIndex)); store.setSelectedElement(draggedElement); }, handleDragDrop: (e: React.DragEvent) => { @@ -125,7 +125,7 @@ export class ElementList extends React.Component { return; } - store.execute(ElementCommand.addChild(element, draggedElement)); + store.execute(ElementLocationCommand.addChild(element, draggedElement)); store.setSelectedElement(draggedElement); }, children: items, diff --git a/src/component/container/pattern-list.tsx b/src/component/container/pattern-list.tsx index 3a5fa70e3..636f6b92e 100644 --- a/src/component/container/pattern-list.tsx +++ b/src/component/container/pattern-list.tsx @@ -1,5 +1,5 @@ import Input from '../../lsg/patterns/input/'; -import { ElementCommand } from '../../store/command/element-command'; +import { ElementLocationCommand } from '../../store/command/element-location-command'; import { PatternFolder } from '../../store/styleguide/folder'; import { action } from 'mobx'; import { observer } from 'mobx-react'; @@ -114,7 +114,7 @@ export class PatternListContainer extends React.Component { pattern, setDefaults: true }); - store.execute(ElementCommand.addSibling(selectedElement, newPageElement)); + store.execute(ElementLocationCommand.addSibling(selectedElement, newPageElement)); store.setSelectedElement(newPageElement); } } diff --git a/src/electron/context-menus.ts b/src/electron/context-menus.ts index 673f43354..84c052289 100644 --- a/src/electron/context-menus.ts +++ b/src/electron/context-menus.ts @@ -1,5 +1,5 @@ import { MenuItemConstructorOptions, remote } from 'electron'; -import { ElementCommand } from '../store/command/element-command'; +import { ElementLocationCommand } from '../store/command/element-location-command'; import { PageElement } from '../store/page/page-element'; import { Store } from '../store/store'; @@ -12,7 +12,7 @@ export function elementMenu(element: PageElement): void { label: 'Cut Element', click: () => { store.setClipboardElement(element); - store.execute(ElementCommand.remove(element)); + store.execute(ElementLocationCommand.remove(element)); } }, { @@ -24,7 +24,7 @@ export function elementMenu(element: PageElement): void { { label: 'Delete element', click: () => { - store.execute(ElementCommand.remove(element)); + store.execute(ElementLocationCommand.remove(element)); } }, { @@ -37,7 +37,7 @@ export function elementMenu(element: PageElement): void { const newPageElement = clipboardElement && clipboardElement.clone(); if (newPageElement) { - store.execute(ElementCommand.addSibling(element, newPageElement)); + store.execute(ElementLocationCommand.addSibling(element, newPageElement)); } } }, @@ -48,7 +48,7 @@ export function elementMenu(element: PageElement): void { const newPageElement = clipboardElement && clipboardElement.clone(); if (newPageElement) { - store.execute(ElementCommand.addChild(element, newPageElement)); + store.execute(ElementLocationCommand.addChild(element, newPageElement)); } } } diff --git a/src/electron/menu.ts b/src/electron/menu.ts index d1952b1c8..de2062ed6 100644 --- a/src/electron/menu.ts +++ b/src/electron/menu.ts @@ -6,7 +6,7 @@ import { remote, WebviewTag } from 'electron'; -import { ElementCommand } from '../store/command/element-command'; +import { ElementLocationCommand } from '../store/command/element-location-command'; import * as FileExtraUtils from 'fs-extra'; import { PageElement } from '../store/page/page-element'; import * as PathUtils from 'path'; @@ -197,7 +197,7 @@ export function createMenu(): void { const selectedElement: PageElement | undefined = store.getSelectedElement(); if (selectedElement && store.isElementFocussed()) { store.setClipboardElement(selectedElement); - store.execute(ElementCommand.remove(selectedElement)); + store.execute(ElementLocationCommand.remove(selectedElement)); } Menu.sendActionToFirstResponder('cut:'); } @@ -223,7 +223,9 @@ export function createMenu(): void { const clipboardElement: PageElement | undefined = store.getClipboardElement(); if (selectedElement && clipboardElement && store.isElementFocussed()) { const newPageElement = clipboardElement.clone(); - store.execute(ElementCommand.addSibling(selectedElement, newPageElement)); + store.execute( + ElementLocationCommand.addSibling(selectedElement, newPageElement) + ); store.setSelectedElement(newPageElement); } Menu.sendActionToFirstResponder('paste:'); @@ -240,7 +242,9 @@ export function createMenu(): void { const selectedElement: PageElement | undefined = store.getSelectedElement(); if (selectedElement && store.isElementFocussed()) { const newPageElement = selectedElement.clone(); - store.execute(ElementCommand.addSibling(selectedElement, newPageElement)); + store.execute( + ElementLocationCommand.addSibling(selectedElement, newPageElement) + ); store.setSelectedElement(newPageElement); } } @@ -269,7 +273,7 @@ export function createMenu(): void { click: () => { const selectedElement: PageElement | undefined = store.getSelectedElement(); if (selectedElement) { - store.execute(ElementCommand.remove(selectedElement)); + store.execute(ElementLocationCommand.remove(selectedElement)); store.setSelectedElement(undefined); } else { if (process.platform === 'darwin') { diff --git a/src/store/command/element-command.ts b/src/store/command/element-command.ts index b7eafa0e2..c729a25bd 100644 --- a/src/store/command/element-command.ts +++ b/src/store/command/element-command.ts @@ -4,158 +4,57 @@ import { PageElement } from '../page/page-element'; import { Store } from '../store'; /** - * A user operation to add or remove a child to/from a parent, or to relocate it. + * A user operation on a page element, ensuring that the page is loaded and references get + * refreshed. */ -export class ElementCommand extends Command { +export abstract class ElementCommand extends Command { /** - * The element to change the parent of, or to remove. + * The element the user operation is performed on. */ - private child: PageElement; + protected element: PageElement; /** * The ID of the element the user operation is performed on, * if the element is already part of a page. */ - private childId: string | undefined; - - /** - * The new position within the parent's children, if a parent is given. - * Leaving out this value puts the child to the end of the parent's children. - */ - private index?: number; + protected elementId: string; /** * The ID of the page the operation is performed on. */ - private pageId: string; - - /** - * The new parent for the child. undefined removes the child. - */ - private parent?: PageElement; - - /** - * The ID ofg the target parent of the child element. - */ - private parentId?: string; - - /** - * The previous position, for undo. - */ - private previousIndex?: number; - - /** - * The previous parent, for undo. - */ - private previousParent?: PageElement; + protected pageId: string; /** - * The ID of the previous parent, for undo. + * Creates a new user operation on a page element. + * @param element The element the user operation is performed on. + * @param propertyId The ID of the property to change. + * @param value The new value for the property. + * @param path A dot ('.') separated optional path within an object property to point to a deep + * property. E.g., setting propertyId to 'image' and path to 'src.srcSet.xs', + * the operation edits 'image.src.srcSet.xs' on the element. */ - private previousParentId?: string | undefined; - - /** - * Creates a new user operation to add or remove a child to/from a parent, or to relocate it. - * @param child The element to change the parent of, or to remove. - * @param parent The new parent for the child. undefined removes the child. - * @param index The new position within the parent's children, if a parent is given. - * Leaving out this value puts the child to the end of the parent's children. - */ - public constructor(child: PageElement, parent?: PageElement, index?: number) { + // tslint:disable-next-line:no-any + public constructor(element: PageElement) { super(); - this.child = child; - this.parent = parent; - this.index = index; - - this.previousParent = child.getParent(); - this.previousIndex = this.previousParent ? child.getIndex() : undefined; + this.element = element; - // Memorize the page IDs. + // Memorize the element and page IDs. // This way, closing and opening a page does not break the command. - const page = child.getPage(); + this.elementId = element.getId(); + const page = element.getPage(); if (page) { this.pageId = page.getId(); - } else if (parent) { - const parentPage = parent.getPage(); - // If the element is not known to the page, memorize the page ID from the target parent. - if (parentPage) { - this.pageId = parentPage.getId(); - } - } - - if (!this.pageId) { - throw new Error( - 'Element commands require either a child already added to a page, or a target parent for a new child' - ); } } - /** - * Creates a command to add a child element to a given parent element - * (and remove it from any other parent). - * @param parent The parent to add the child to. - * @param child The child element to add. - * @param index The 0-based new position within the parent's children. - * Leaving out the position adds it at the end of the list. - * @return The new element command. To register and run the command it, call Store.execute(). - * @see Store.execute() - */ - public static addChild(parent: PageElement, child: PageElement, index?: number): ElementCommand { - return new ElementCommand(child, parent, index); - } - - /** - * Creates a command to add a page element as another child of an element's parent, - * directly after that element. On execution, also removes the element from any previous parent. - * @param newSibling The element to add at a given location. - * @param location The element to add the new sibling after. - * @return The new element command. To register and run the command it, call Store.execute(). - * @see Store.execute() - */ - public static addSibling(newSibling: PageElement, location: PageElement): ElementCommand { - const parent: PageElement | undefined = location.getParent(); - return new ElementCommand(newSibling, parent, parent ? location.getIndex() + 1 : undefined); - } - - /** - * Creates a command to remove a page element from its parent. - * You may later re-add it using a command created with addChild() or setParent(). - * @param element The element to remove from its parent. - * @return The new element command. To register and run the command it, call Store.execute(). - * @see addChild() - * @see setParent() - * @see Store.execute() - */ - public static remove(element: PageElement): ElementCommand { - return new ElementCommand(element); - } - - /** - * Creates a command to set a new parent for this element (and remove it - * from its previous parent). If no parent is provided, only removes it from its parent. - * @param child The element to set the new parent of. - * @param parent The (optional) new parent for the element. - * @param index The 0-based new position within the children of the new parent. - * Leaving out the position adds it at the end of the list. - * @return The new element command. To register and run the command it, call Store.execute(). - * @see Store.execute() - */ - public static setParent( - child: PageElement, - parent: PageElement, - index?: number - ): ElementCommand { - return new ElementCommand(child, parent, index); - } - /** * Ensures that the page of this command is currently open in the store, and opens it if not. - * Then ensures that the child element is used from that open page. + * Then ensures that the element is used from that open page. * @return Whether the operation was successful. On failure, the execute/undo should abort. */ - protected ensurePageAndChild(): boolean { + protected ensurePageAndElement(): boolean { let currentPage: Page | undefined = Store.getInstance().getCurrentPage(); if (!currentPage || currentPage.getId() !== this.pageId) { if (!Store.getInstance().openPage(this.pageId)) { @@ -164,30 +63,12 @@ export class ElementCommand extends Command { currentPage = Store.getInstance().getCurrentPage() as Page; } - if (this.childId) { - const child: PageElement | undefined = currentPage.getElementById(this.childId); - if (!child) { - return false; - } - this.child = child; - } - - if (this.parentId) { - const parent: PageElement | undefined = currentPage.getElementById(this.parentId); - if (!parent) { - return false; - } - this.parent = parent; - } - - if (this.previousParentId) { - const previousParent: PageElement | undefined = currentPage.getElementById( - this.previousParentId - ); - if (!previousParent) { + if (this.elementId) { + const element: PageElement | undefined = currentPage.getElementById(this.elementId); + if (!element) { return false; } - this.previousParent = previousParent; + this.element = element; } return true; @@ -197,15 +78,12 @@ export class ElementCommand extends Command { * @inheritDoc */ public execute(): boolean { - if (!this.ensurePageAndChild()) { + if (!this.ensurePageAndElement()) { return false; } - this.child.setParent(this.parent, this.index); - this.memorizeElementIds(); - - if (this.child.getPage()) { - Store.getInstance().setSelectedElement(this.child); + if (this.element.getPage()) { + Store.getInstance().setSelectedElement(this.element); } return true; @@ -214,33 +92,29 @@ export class ElementCommand extends Command { /** * @inheritDoc */ - public getType(): string { - return 'element-location'; - } + public maybeMergeWith(previousCommand: Command): boolean { + if (previousCommand.getType() !== this.getType()) { + return false; + } - /** - * Stores the ID of the page elements if they are currently added to the page, - * to prevent issues with undo/redo when pages are closed and reopened. - */ - private memorizeElementIds(): void { - this.childId = this.getElementIdIfPartOfPage(this.child); - this.parentId = this.getElementIdIfPartOfPage(this.parent); - this.previousParentId = this.getElementIdIfPartOfPage(this.previousParent); + const previousElementCommand: ElementCommand = previousCommand as ElementCommand; + if (previousElementCommand.elementId !== this.elementId) { + return false; + } + + return true; } /** * @inheritDoc */ public undo(): boolean { - if (!this.ensurePageAndChild()) { + if (!this.ensurePageAndElement()) { return false; } - this.child.setParent(this.previousParent, this.previousIndex); - this.memorizeElementIds(); - - if (this.child.getPage()) { - Store.getInstance().setSelectedElement(this.child); + if (this.element.getPage()) { + Store.getInstance().setSelectedElement(this.element); } return true; diff --git a/src/store/command/element-location-command.ts b/src/store/command/element-location-command.ts new file mode 100644 index 000000000..354521db7 --- /dev/null +++ b/src/store/command/element-location-command.ts @@ -0,0 +1,217 @@ +import { Command } from './command'; +import { ElementCommand } from './element-command'; +import { Page } from '../page/page'; +import { PageElement } from '../page/page-element'; +import { Store } from '../store'; + +/** + * A user operation to add or remove a child to/from a parent, or to relocate it. + */ +export class ElementLocationCommand extends ElementCommand { + /** + * The new position within the parent's children, if a parent is given. + * Leaving out this value puts the child to the end of the parent's children. + */ + protected index?: number; + + /** + * The new parent for the child. undefined removes the child. + */ + protected parent?: PageElement; + + /** + * The ID ofg the target parent of the child element. + */ + protected parentId?: string; + + /** + * The previous position, for undo. + */ + protected previousIndex?: number; + + /** + * The previous parent, for undo. + */ + protected previousParent?: PageElement; + + /** + * The ID of the previous parent, for undo. + */ + protected previousParentId?: string | undefined; + + /** + * Creates a new user operation to add or remove a child to/from a parent, or to relocate it. + * @param element The element the user operation is performed on. + * @param parent The new parent for the child. undefined removes the child. + * @param index The new position within the parent's children, if a parent is given. + * Leaving out this value puts the child to the end of the parent's children. + */ + public constructor(element: PageElement, parent?: PageElement, index?: number) { + super(element); + + this.parent = parent; + this.index = index; + + this.previousParent = element.getParent(); + this.previousIndex = this.previousParent ? element.getIndex() : undefined; + + // Memorize the page IDs of the new parent, if the element has no parent. + // This way, closing and opening a page does not break the command. + + if (!this.pageId && parent) { + const parentPage = parent.getPage(); + // If the element is not known to the page, memorize the page ID from the target parent. + if (parentPage) { + this.pageId = parentPage.getId(); + } + } + + if (!this.pageId) { + throw new Error( + 'Element location commands require either a child already added to a page,' + + ' or a target parent for a new child' + ); + } + } + + /** + * Creates a command to add a child element to a given parent element + * (and remove it from any other parent). + * @param parent The parent to add the child to. + * @param child The child element to add. + * @param index The 0-based new position within the parent's children. + * Leaving out the position adds it at the end of the list. + * @return The new element command. To register and run the command it, call Store.execute(). + * @see Store.execute() + */ + public static addChild(parent: PageElement, child: PageElement, index?: number): ElementCommand { + return new ElementLocationCommand(child, parent, index); + } + + /** + * Creates a command to add a page element as another child of an element's parent, + * directly after that element. On execution, also removes the element from any previous parent. + * @param newSibling The element to add at a given location. + * @param location The element to add the new sibling after. + * @return The new element command. To register and run the command it, call Store.execute(). + * @see Store.execute() + */ + public static addSibling(newSibling: PageElement, location: PageElement): ElementCommand { + const parent: PageElement | undefined = location.getParent(); + return new ElementLocationCommand( + newSibling, + parent, + parent ? location.getIndex() + 1 : undefined + ); + } + + /** + * Creates a command to remove a page element from its parent. + * You may later re-add it using a command created with addChild() or setParent(). + * @param element The element to remove from its parent. + * @return The new element command. To register and run the command it, call Store.execute(). + * @see addChild() + * @see setParent() + * @see Store.execute() + */ + public static remove(element: PageElement): ElementCommand { + return new ElementLocationCommand(element); + } + + /** + * Creates a command to set a new parent for this element (and remove it + * from its previous parent). If no parent is provided, only removes it from its parent. + * @param child The element to set the new parent of. + * @param parent The (optional) new parent for the element. + * @param index The 0-based new position within the children of the new parent. + * Leaving out the position adds it at the end of the list. + * @return The new element command. To register and run the command it, call Store.execute(). + * @see Store.execute() + */ + public static setParent( + child: PageElement, + parent: PageElement, + index?: number + ): ElementCommand { + return new ElementLocationCommand(child, parent, index); + } + + /** + * @inheritDoc + */ + protected ensurePageAndElement(): boolean { + super.ensurePageAndElement(); + + const currentPage: Page | undefined = Store.getInstance().getCurrentPage() as Page; + if (this.parentId) { + const parent: PageElement | undefined = currentPage.getElementById(this.parentId); + if (!parent) { + return false; + } + this.parent = parent; + } + + if (this.previousParentId) { + const previousParent: PageElement | undefined = currentPage.getElementById( + this.previousParentId + ); + if (!previousParent) { + return false; + } + this.previousParent = previousParent; + } + + return true; + } + + /** + * @inheritDoc + */ + public execute(): boolean { + if (!super.execute()) { + return false; + } + + this.element.setParent(this.parent, this.index); + this.memorizeElementIds(); + + return true; + } + + /** + * @inheritDoc + */ + public getType(): string { + return 'element-location'; + } + + /** + * @inheritDoc + */ + public maybeMergeWith(previousCommand: Command): boolean { + return false; + } + + /** + * Stores the ID of the page elements if they are currently added to the page, + * to prevent issues with undo/redo when pages are closed and reopened. + */ + private memorizeElementIds(): void { + this.parentId = this.getElementIdIfPartOfPage(this.parent); + this.previousParentId = this.getElementIdIfPartOfPage(this.previousParent); + } + + /** + * @inheritDoc + */ + public undo(): boolean { + if (!super.undo()) { + return false; + } + + this.element.setParent(this.previousParent, this.previousIndex); + this.memorizeElementIds(); + + return true; + } +} diff --git a/src/store/command/element-name-command.ts b/src/store/command/element-name-command.ts new file mode 100644 index 000000000..85f371355 --- /dev/null +++ b/src/store/command/element-name-command.ts @@ -0,0 +1,82 @@ +import { Command } from './command'; +import { ElementCommand } from './element-command'; +import { PageElement } from '../page/page-element'; + +/** + * A user operation to set the name of a page element. + */ +export class ElementNameCommand extends ElementCommand { + /** + * The new name for the page element. + */ + private name: string; + + /** + * The previous value, for undo. + */ + private previousName: string; + + /** + * Creates a new user operation to set the name of a page element. + * @param element The element the user operation is performed on. + * @param name The new name for the page element. + */ + // tslint:disable-next-line:no-any + public constructor(element: PageElement, name: string) { + super(element); + + this.name = name; + this.previousName = element.getName(); + + if (!this.pageId) { + throw new Error( + 'Element name commands require that the element is already added to a page' + ); + } + } + + /** + * @inheritDoc + */ + public execute(): boolean { + if (!super.execute()) { + return false; + } + + this.element.setName(this.name); + return true; + } + + /** + * @inheritDoc + */ + public getType(): string { + return 'element-name'; + } + + /** + * @inheritDoc + */ + public maybeMergeWith(previousCommand: Command): boolean { + if (!super.maybeMergeWith(previousCommand)) { + return false; + } + + const previousElementCommand = previousCommand as ElementNameCommand; + + this.previousName = previousElementCommand.previousName; + return true; + } + + /** + * @inheritDoc + */ + public undo(): boolean { + if (!super.undo()) { + return false; + } + + this.element.setName(this.previousName); + return true; + } +} diff --git a/src/store/command/property-value-command.ts b/src/store/command/property-value-command.ts index 55a2948a1..ca3a2ac22 100644 --- a/src/store/command/property-value-command.ts +++ b/src/store/command/property-value-command.ts @@ -1,45 +1,28 @@ import { Command } from './command'; -import { Page } from '../page/page'; +import { ElementCommand } from './element-command'; import { PageElement } from '../page/page-element'; -import { Store } from '../store'; /** * A user operation to set the value of a page element property. */ -export class PropertyValueCommand extends Command { - /** - * The element the user operation is performed on. - */ - private element: PageElement; - - /** - * The ID of the element the user operation is performed on, - * if the element is already part of a page. - */ - private elementId: string; - - /** - * The ID of the page the operation is performed on. - */ - private pageId: string; - +export class PropertyValueCommand extends ElementCommand { /** * A dot ('.') separated optional path within an object property to point to a deep * property. E.g., setting propertyId to 'image' and path to 'src.srcSet.xs', * the operation edits 'image.src.srcSet.xs' on the element. */ - private path?: string; + protected path?: string; /** * The previous value, for undo. */ // tslint:disable-next-line:no-any - private previousValue: any; + protected previousValue: any; /** * The ID of the property to modify. */ - private propertyId: string; + protected propertyId: string; /** * Whether this property value editing is complete now, so that similar value changes do not @@ -50,11 +33,11 @@ export class PropertyValueCommand extends Command { protected sealed: boolean = false; // tslint:disable-next-line:no-any - private value: any; + protected value: any; /** * Creates a new user operation to set the value of a page element property. - * @param element The element to change a property value of. + * @param element The element the user operation is performed on. * @param propertyId The ID of the property to change. * @param value The new value for the property. * @param path A dot ('.') separated optional path within an object property to point to a deep @@ -63,67 +46,29 @@ export class PropertyValueCommand extends Command { */ // tslint:disable-next-line:no-any public constructor(element: PageElement, propertyId: string, value: any, path?: string) { - super(); + super(element); - this.element = element; this.propertyId = propertyId; this.value = value; this.path = path; this.previousValue = element.getPropertyValue(propertyId, path); - // Memorize the element and page IDs. - // This way, closing and opening a page does not break the command. - - this.elementId = element.getId(); - const page = element.getPage(); - if (page) { - this.pageId = page.getId(); - } else { + if (!this.pageId) { throw new Error( 'Property value commands require that the element is already added to a page' ); } } - /** - * Ensures that the page of this command is currently open in the store, and opens it if not. - * Then ensures that the element is used from that open page. - * @return Whether the operation was successful. On failure, the execute/undo should abort. - */ - protected ensurePageAndElement(): boolean { - let currentPage: Page | undefined = Store.getInstance().getCurrentPage(); - if (!currentPage || currentPage.getId() !== this.pageId) { - if (!Store.getInstance().openPage(this.pageId)) { - return false; - } - currentPage = Store.getInstance().getCurrentPage() as Page; - } - - if (this.elementId) { - const element: PageElement | undefined = currentPage.getElementById(this.elementId); - if (!element) { - return false; - } - this.element = element; - } - - return true; - } - /** * @inheritDoc */ public execute(): boolean { - if (!this.ensurePageAndElement()) { + if (!super.execute()) { return false; } this.element.setPropertyValue(this.propertyId, this.value, this.path); - - if (this.element.getPage()) { - Store.getInstance().setSelectedElement(this.element); - } - return true; } @@ -131,21 +76,20 @@ export class PropertyValueCommand extends Command { * @inheritDoc */ public getType(): string { - return 'set-property-value'; + return 'property-value'; } /** * @inheritDoc */ public maybeMergeWith(previousCommand: Command): boolean { - if (previousCommand.getType() !== this.getType()) { + if (!super.maybeMergeWith(previousCommand)) { return false; } const previousPropertyCommand: PropertyValueCommand = previousCommand as PropertyValueCommand; if ( previousPropertyCommand.sealed || - previousPropertyCommand.element.getId() !== this.element.getId() || previousPropertyCommand.propertyId !== this.propertyId || previousPropertyCommand.path !== this.path ) { @@ -170,16 +114,11 @@ export class PropertyValueCommand extends Command { * @inheritDoc */ public undo(): boolean { - if (!this.ensurePageAndElement()) { + if (!super.undo()) { return false; } this.element.setPropertyValue(this.propertyId, this.previousValue, this.path); - - if (this.element.getPage()) { - Store.getInstance().setSelectedElement(this.element); - } - return true; } } diff --git a/src/store/page/page-element.ts b/src/store/page/page-element.ts index 388c35f30..b7364aef3 100644 --- a/src/store/page/page-element.ts +++ b/src/store/page/page-element.ts @@ -34,6 +34,11 @@ export class PageElement { */ @MobX.observable private id: string; + /** + * The assigned name of the page element, initially the pattern's human-friendly name. + */ + @MobX.observable private name: string; + /** * The page this element belongs to. */ @@ -69,6 +74,10 @@ export class PageElement { this.id = properties.id ? properties.id : Uuid.v4(); this.pattern = properties.pattern; + if (this.name === undefined && this.pattern) { + this.name = this.pattern.getName(); + } + if (properties.setDefaults && this.pattern) { this.pattern.getProperties().forEach(property => { this.setPropertyValue(property.getId(), property.getDefaultValue()); @@ -116,6 +125,10 @@ export class PageElement { const element = new PageElement({ id: json.uuid as string, pattern, parent }); + if (json.name !== undefined) { + element.name = json.name as string; + } + if (json.properties) { Object.keys(json.properties as JsonObject).forEach((propertyId: string) => { const value: JsonValue = (json.properties as JsonObject)[propertyId]; @@ -220,6 +233,14 @@ export class PageElement { return this.parent.children.indexOf(this); } + /** + * Returns the assigned name of the page element, initially the pattern's human-friendly name. + * @return The assigned name of the page element. + */ + public getName(): string { + return this.name; + } + /** * Returns the page this element belongs to. * @return The page this element belongs to. @@ -338,6 +359,14 @@ export class PageElement { this.setParent(this.parent, index); } + /** + * Sets the assigned name of the page element, initially the pattern's human-friendly name. + * @param name The assigned name of the page element. + */ + public setName(name: string): void { + this.name = name; + } + /** * Sets a new parent for this element (and removes it from its previous parent). * If no parent is provided, only removes it from its parent. @@ -432,6 +461,7 @@ export class PageElement { const json: JsonObject = { _type: 'pattern', uuid: this.id, + name: this.name, pattern: this.pattern && this.pattern.getId() }; diff --git a/src/store/styleguide/property/property.ts b/src/store/styleguide/property/property.ts index 34896d164..c539d27f6 100644 --- a/src/store/styleguide/property/property.ts +++ b/src/store/styleguide/property/property.ts @@ -146,7 +146,8 @@ export abstract class Property { } /** - * Returns the technical ID of this property (e.g. the property name in the TypeScript props interface). + * Returns the technical ID of this property (e.g. the property name in the TypeScript props + * interface). * @return The technical ID. */ public getId(): string { diff --git a/src/styleguide/renderer/react/preview.tsx b/src/styleguide/renderer/react/preview.tsx index 2ecfa729d..7c995a6c3 100644 --- a/src/styleguide/renderer/react/preview.tsx +++ b/src/styleguide/renderer/react/preview.tsx @@ -42,8 +42,12 @@ class PatternWrapper extends React.Component; + return ( + + ); } else { return this.props.children; } @@ -143,7 +147,7 @@ class Preview extends React.Component { const reactElement = React.createElement(patternFactory, componentProps); return this.createWrapper(pageElement, reactElement); } catch (error) { - return ; + return ; } } else { // The model is an object, but not a pattern declaration.