Skip to content

Commit

Permalink
#2140 WYSIWYG comment should show current parameter selections (#2143)
Browse files Browse the repository at this point in the history
Signed-off-by: CTomlyn <[email protected]>
  • Loading branch information
tomlyn authored Sep 6, 2024
1 parent 74ddb23 commit d65836b
Show file tree
Hide file tree
Showing 13 changed files with 145 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe("Common Canvas Text Toolbar renders correctly", () => {

it("should render <Toolbar> inside <CommonCanvasTextToolbar/> when open", () => {
wrapper = createIntlCommonCanvasTextToolbar({}, canvasController);
canvasController.openTextToolbar(100, 200, MARKDOWN, () => { /**/ });
canvasController.openTextToolbar(100, 200, [], MARKDOWN, () => { /**/ });
wrapper.update();

expect(wrapper.find(CommonCanvasTextToolbar)).to.have.length(1);
Expand All @@ -63,7 +63,7 @@ describe("Common Canvas Text Toolbar renders correctly", () => {

it("should render text toolbar in new position when moved", () => {
wrapper = createIntlCommonCanvasTextToolbar({}, canvasController);
canvasController.openTextToolbar(100, 200, () => { /**/ });
canvasController.openTextToolbar(100, 200, [], () => { /**/ });
wrapper.update();

expect(wrapper.find(".text-toolbar").get(0).props.style.left).to.equal(100);
Expand All @@ -78,7 +78,7 @@ describe("Common Canvas Text Toolbar renders correctly", () => {

it("should NOT render <Toolbar/> after it is closed", () => {
wrapper = createIntlCommonCanvasTextToolbar({}, canvasController);
canvasController.openTextToolbar(100, 200, () => { /**/ });
canvasController.openTextToolbar(100, 200, [], () => { /**/ });
wrapper.update();

expect(wrapper.find(CommonCanvasTextToolbar)).to.have.length(1);
Expand Down
16 changes: 11 additions & 5 deletions canvas_modules/common-canvas/src/color-picker/color-picker.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 Elyra Authors
* Copyright 2017-2024 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -123,11 +123,17 @@ class ColorPicker extends React.Component {
render() {
this.logger.log("render");
if (this.props.subPanelData.type === WYSIWYG) {
const colorDivs = colorSetArray.map((c, i) =>
(<div key={"key" + i} ref={this.refss[i]} tabIndex={"-1"} data-color={c}

const colorDivs = colorSetArray.map((c, i) => {
let className = "color-picker-item" + (c === "transparent" ? " color-transparent" : "");
className += this.props.subPanelData.selectedColor === c ? " selected" : "";

return (<div key={"key" + i} ref={this.refss[i]} tabIndex={"-1"}
data-color={c}
style={{ backgroundColor: c }}
className={"color-picker-item" + (c === "transparent" ? " color-transparent" : "") }
/>));
className={className}
/>);
});

const rowCount = Math.ceil(this.totalColors / this.colorsPerRow);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 Elyra Authors
* Copyright 2017-2024 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -49,6 +49,10 @@
background:
linear-gradient(to top left, $icon-inverse calc(50% - 1.2px), $icon-primary 50%, $icon-inverse calc(50% + 1.2px), $icon-inverse 100%);
}

&.selected {
outline: solid $layer-selected-inverse 2px;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import { LINK_SELECTION_NONE, LINK_SELECTION_DETACHABLE,
SNAP_TO_GRID_NONE, SUPER_NODE, WYSIWYG
} from "./constants/canvas-constants";

import { cloneDeep } from "lodash";

// Global instance ID counter
var commonCanvasControllerInstanceId = 0;

Expand Down Expand Up @@ -2065,8 +2067,8 @@ export default class CanvasController {
}
}

openTextToolbar(xPos, yPos, contentType, actionHandler, blurHandler) {
this.objectModel.setTextToolbarDef({ isOpen: true, pos_x: xPos, pos_y: yPos, contentType, actionHandler, blurHandler });
openTextToolbar(xPos, yPos, formats, contentType, actionHandler, blurHandler) {
this.objectModel.setTextToolbarDef({ isOpen: true, pos_x: xPos, pos_y: yPos, formats, contentType, actionHandler, blurHandler });
}

closeTextToolbar() {
Expand All @@ -2077,6 +2079,10 @@ export default class CanvasController {
this.objectModel.setTextToolbarDef({ pos_x: xPos, pos_y: yPos });
}

updateTextToolbarFormats(formats) {
this.objectModel.setTextToolbarDef({ formats: cloneDeep(formats) }); // Clone to force mapToState refresh.
}

// Processes the drop of an 'external' object, either from the desktop or
// elsewhere on the browser page, onto the canvas.
// dropData - The data describing the object being dropped
Expand Down
80 changes: 68 additions & 12 deletions canvas_modules/common-canvas/src/common-canvas/cc-text-toolbar.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 Elyra Authors
* Copyright 2017-2024 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -102,8 +102,9 @@ class CommonCanvasTextToolbar extends React.Component {
const underlineLabel = this.getLabel("texttoolbar.underline");
const strikethroughLabel = this.getLabel("texttoolbar.strikethroughAction");

// Set up array for sub-menus. isSelected is set to true for any default option.
const subMenuFont = [
{ action: "font-ibm-plex-sans", label: this.getLabel("texttoolbar.fontIBMPlexSans"), enable: true },
{ action: "font-ibm-plex-sans", label: this.getLabel("texttoolbar.fontIBMPlexSans"), enable: true, isSelected: true },
{ action: "font-ibm-plex-serif", label: this.getLabel("texttoolbar.fontIBMPlexSerif"), enable: true },
{ action: "font-ibm-plex-sans-condensed", label: this.getLabel("texttoolbar.fontIBMPlexSansCon"), enable: true },
{ action: "font-ibm-plex-mono", label: this.getLabel("texttoolbar.fontIBMPlexMono"), enable: true },
Expand All @@ -118,7 +119,7 @@ class CommonCanvasTextToolbar extends React.Component {
const subMenuTextSize = [
{ action: "text-size-10", label: "10", enable: true },
{ action: "text-size-11", label: "11", enable: true },
{ action: "text-size-12", label: "12", enable: true },
{ action: "text-size-12", label: "12", enable: true, isSelected: true },
{ action: "text-size-14", label: "14", enable: true },
{ action: "text-size-18", label: "18", enable: true },
{ action: "text-size-24", label: "24", enable: true },
Expand All @@ -131,22 +132,45 @@ class CommonCanvasTextToolbar extends React.Component {
];

const subMenuAlignHorizontal = [
{ action: "align-left", label: this.getLabel("texttoolbar.alignHorizLeft"), enable: true, iconEnabled: (<TextAlignLeft size={32} />) },
{ action: "align-left", label: this.getLabel("texttoolbar.alignHorizLeft"), enable: true, iconEnabled: (<TextAlignLeft size={32} />), isSelected: true },
{ action: "align-center", label: this.getLabel("texttoolbar.alignHorizCenter"), enable: true, iconEnabled: (<TextAlignCenter size={32} />) },
{ action: "align-right", label: this.getLabel("texttoolbar.alignHorizRight"), enable: true, iconEnabled: (<TextAlignRight size={32} />) }
];

const subMenuAlignVertical = [
{ action: "align-top", label: this.getLabel("texttoolbar.alignVertTop"), enable: true, iconEnabled: (<AlignBoxTopCenter size={32} />) },
{ action: "align-top", label: this.getLabel("texttoolbar.alignVertTop"), enable: true, iconEnabled: (<AlignBoxTopCenter size={32} />), isSelected: true },
{ action: "align-middle", label: this.getLabel("texttoolbar.alignVertMiddle"), enable: true, iconEnabled: (<AlignBoxMiddleCenter size={32} />) },
{ action: "align-bottom", label: this.getLabel("texttoolbar.alignVertBottom"), enable: true, iconEnabled: (<AlignBoxBottomCenter size={32} />) }
];

const subMenuOutline = [
{ action: "outline-none", label: this.getLabel("texttoolbar.outlineNone"), enable: true },
{ action: "outline-solid", label: this.getLabel("texttoolbar.outlineSolid"), enable: true }
{ action: "outline-solid", label: this.getLabel("texttoolbar.outlineSolid"), enable: true, isSelected: true }
];

// In the arrays above the default option has its isSelected field set to true. We
// now override the isSelected field, if necessary, for all menus, based on whether
// the corresponding format has been set in the formats array. So if, for example, the
// font is set to 'Comic Sans' the element for that font in subMenuFont will have its
// isSelected field set to true and the element for the default font or previously
// selected font will have its isSelected field set to false.
this.setSelectedMenuElement("fontType", this.props.formats, subMenuFont);
this.setSelectedMenuElement("textSize", this.props.formats, subMenuTextSize);
this.setSelectedMenuElement("alignHorizontally", this.props.formats, subMenuAlignHorizontal);
this.setSelectedMenuElement("alignVertically", this.props.formats, subMenuAlignVertical);
this.setSelectedMenuElement("outlineStyle", this.props.formats, subMenuOutline);

// Get current values (or defaults) for text and background color.
const selectedTextColor = (this.getFormatValue("textColor", this.props.formats) || "#000000");
const selectedBackgroundColor = (this.getFormatValue("backgroundColor", this.props.formats) || "#FFFFFF");

// Get the current values (or defaults) for bold/italics/underline/striketrough attributes
const boldSeletced = (Boolean)(this.getFormatType("bold", this.props.formats));
const italicsSelected = (Boolean)(this.getFormatType("italics", this.props.formats));
const textDec = this.getFormatValue("textDecoration", this.props.formats);
const underlineSelected = textDec?.includes("underline");
const strikethroughSelected = textDec?.includes("strikethrough");

return {
leftBar: [
{ action: "submenu-font",
Expand All @@ -163,10 +187,10 @@ class CommonCanvasTextToolbar extends React.Component {
subMenu: subMenuTextSize,
closeSubAreaOnClick: true
},
{ action: "bold", label: boldLabel, enable: true, iconEnabled: (<TextBold size={32} />) },
{ action: "italics", label: italicsLabel, enable: true, iconEnabled: (<TextItalic size={32} />) },
{ action: "underline", label: underlineLabel, enable: true, iconEnabled: (<TextUnderline size={32} />) },
{ action: "strikethrough", label: strikethroughLabel, enable: true, iconEnabled: (<TextStrikethrough size={32} />) },
{ action: "bold", label: boldLabel, enable: true, iconEnabled: (<TextBold size={32} />), isSelected: boldSeletced },
{ action: "italics", label: italicsLabel, enable: true, iconEnabled: (<TextItalic size={32} />), isSelected: italicsSelected },
{ action: "underline", label: underlineLabel, enable: true, iconEnabled: (<TextUnderline size={32} />), isSelected: underlineSelected },
{ action: "strikethrough", label: strikethroughLabel, enable: true, iconEnabled: (<TextStrikethrough size={32} />), isSelected: strikethroughSelected },
{ divider: true },
{ action: "submenu-text-color",
label: this.getLabel("texttoolbar.colorText"),
Expand All @@ -175,6 +199,7 @@ class CommonCanvasTextToolbar extends React.Component {
subPanel: ColorPicker,
subPanelData: {
type: WYSIWYG,
selectedColor: selectedTextColor,
clickActionHandler: (color, evt) => this.props.actionHandler("text-color", evt, color)
},
closeSubAreaOnClick: true
Expand All @@ -200,6 +225,7 @@ class CommonCanvasTextToolbar extends React.Component {
subPanel: ColorPicker,
subPanelData: {
type: WYSIWYG,
selectedColor: selectedBackgroundColor,
clickActionHandler: (color, evt) => this.props.actionHandler("background-color", evt, color)
},
closeSubAreaOnClick: true
Expand All @@ -215,6 +241,32 @@ class CommonCanvasTextToolbar extends React.Component {
};
}

// Sets the isSelected field to true of the element in the menu
// passed in corresponding to the currently specified value for that menu
// in the formats array,
setSelectedMenuElement(type, formats, menu) {
const value = this.getFormatValue(type, formats);
if (value) {
menu.forEach((me) => (me.isSelected = (me.action === value)));
}
}

// Returns the value for the format type passed in from the array of
// formats passed in.
getFormatValue(type, formats) {
const format = this.getFormatType(type, formats);
return format?.value;
}

// Returns the format for the type passed in from the array of
// formats passed in.
getFormatType(type, formats) {
if (formats) {
return formats.find((f) => f.type === type);
}
return null;
}

getTextToolbar() {
if (this.props.contentType === MARKDOWN) {
return this.getMarkdownToolbar();
Expand All @@ -233,7 +285,9 @@ class CommonCanvasTextToolbar extends React.Component {

if (this.props.isOpen) {
textToolbar = (
<div className={"text-toolbar floating-toolbar"} style={{ left: this.props.pos_x, top: this.props.pos_y }} onBlur={this.props.blurHandler}>
<div className={"text-toolbar floating-toolbar"} style={{ left: this.props.pos_x, top: this.props.pos_y }}
onBlur={this.props.blurHandler}
>
<Toolbar
config={this.getTextToolbar()}
instanceId={this.props.canvasController.getInstanceId()}
Expand All @@ -254,12 +308,13 @@ CommonCanvasTextToolbar.propTypes = {
// Provided by CommonCanvas
intl: PropTypes.object.isRequired,
canvasController: PropTypes.object.isRequired,
containingDivId: PropTypes.string.isRequired,
containingDivId: PropTypes.string,

// Provided by redux
isOpen: PropTypes.bool.isRequired,
pos_x: PropTypes.number,
pos_y: PropTypes.number,
formats: PropTypes.array,
contentType: PropTypes.oneOf([MARKDOWN, WYSIWYG]),
actionHandler: PropTypes.func,
blurHandler: PropTypes.func
Expand All @@ -269,6 +324,7 @@ const mapStateToProps = (state, ownProps) => ({
isOpen: state.texttoolbar.isOpen,
pos_x: state.texttoolbar.pos_x,
pos_y: state.texttoolbar.pos_y,
formats: state.texttoolbar.formats,
contentType: state.texttoolbar.contentType,
actionHandler: state.texttoolbar.actionHandler,
blurHandler: state.texttoolbar.blurHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ export default class SvgCanvasTextArea {
if (d.contentType === WYSIWYG) {
this.canvasController.openTextToolbar(
pos.x, pos.y,
this.editingTextData.newFormats,
WYSIWYG,
this.wysiwygActionHandler.bind(this),
this.blurInTextToolbar.bind(this)
Expand All @@ -137,6 +138,7 @@ export default class SvgCanvasTextArea {
} else if (this.config.enableMarkdownInComments) {
this.canvasController.openTextToolbar(
pos.x, pos.y,
null,
MARKDOWN,
this.markdownActionHandler.bind(this),
this.blurInTextToolbar.bind(this)
Expand Down Expand Up @@ -263,6 +265,7 @@ export default class SvgCanvasTextArea {
} else if (action === "bold" || action === "italics") {
this.toggleFormat(action);
}
this.canvasController.updateTextToolbarFormats(this.editingTextData.newFormats);
}

// Sets the text color appropriately for the background color passed in.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import classNames from "classnames";
import { StopFilledAlt, Play, Undo, Redo, Chat, ChatOff, Result,
Cut, Copy, Paste, Edit, ColorPalette, Maximize, Minimize,
Launch, AddComment, TrashCan, ZoomIn, ZoomOut,
ChevronRight, ChevronDown, ChevronUp,
Checkmark, ChevronRight, ChevronDown, ChevronUp,
CenterToFit, OpenPanelFilledLeft } from "@carbon/react/icons";
import { TOOLBAR_STOP, TOOLBAR_RUN, TOOLBAR_UNDO, TOOLBAR_REDO,
TOOLBAR_CUT, TOOLBAR_COPY, TOOLBAR_PASTE, TOOLBAR_CLIPBOARD,
Expand Down Expand Up @@ -210,6 +210,8 @@ class ToolbarButtonItem extends React.Component {

const mainClassName = actionObj.purpose ? "content-main dual" : "content-main";

const checkMark = this.props.actionObj.isSelected && this.props.isInMenu ? (<div className={"checkmark"}> <Checkmark /></div>) : null;

let buttonContent = (
<div className={itemContentClassName}>
<div className={mainClassName}>
Expand All @@ -219,6 +221,7 @@ class ToolbarButtonItem extends React.Component {
{textContent}
</div>
{chevronDiv}
{checkMark}
</div>
);

Expand All @@ -245,7 +248,7 @@ class ToolbarButtonItem extends React.Component {
return button;
}

// Returns a civ containing a chevron icon. If the action icon is displaying
// Returns a <div> containing a chevron icon. If the action icon is displaying
// a sub-menu or sub-panel. The chevron will:
// * point right if this action item is in a drop down menu.
// * point down and be regular size if this action item is displayed with
Expand Down
11 changes: 10 additions & 1 deletion canvas_modules/common-canvas/src/toolbar/toolbar-sub-menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ class ToolbarSubMenu extends React.Component {
}

if (this.state.focusAction === "subarea") {
this.setFocusOnFirstItem();
const selectedItem = this.getFirstCheckedItem();
if (selectedItem) {
this.setFocusAction(selectedItem.action);
} else {
this.setFocusOnFirstItem();
}
}
}

Expand Down Expand Up @@ -165,6 +170,10 @@ class ToolbarSubMenu extends React.Component {
return focuableActions[0];
}

getFirstCheckedItem() {
return this.props.subMenuActions.find((a) => a.isSelected);
}

// Generates an array of JSX objects for a sub-menu defined by the
// prop subMenuActions parameter array.
generateSubMenuItems() {
Expand Down
Loading

0 comments on commit d65836b

Please sign in to comment.