mirror of
https://github.com/google/blockly.git
synced 2026-01-05 08:00:09 +01:00
fix: comment position in RTL (#7934)
* fix: how comments are laid out in RTL * fix: comment positioning with JSON * fix: comment positioning with XML
This commit is contained in:
@@ -19,8 +19,11 @@ export class CommentView implements IRenderedElement {
|
||||
/** The root group element of the comment view. */
|
||||
private svgRoot: SVGGElement;
|
||||
|
||||
/** The group containing all of the top bar elements. */
|
||||
private topBarGroup: SVGGElement;
|
||||
|
||||
/** The rect background for the top bar. */
|
||||
private topBar: SVGRectElement;
|
||||
private topBarBackground: SVGRectElement;
|
||||
|
||||
/** The delete icon that goes in the top bar. */
|
||||
private deleteIcon: SVGImageElement;
|
||||
@@ -97,7 +100,8 @@ export class CommentView implements IRenderedElement {
|
||||
});
|
||||
|
||||
({
|
||||
topBar: this.topBar,
|
||||
topBarGroup: this.topBarGroup,
|
||||
topBarBackground: this.topBarBackground,
|
||||
deleteIcon: this.deleteIcon,
|
||||
foldoutIcon: this.foldoutIcon,
|
||||
textPreview: this.textPreview,
|
||||
@@ -115,6 +119,9 @@ export class CommentView implements IRenderedElement {
|
||||
|
||||
// Set size to the default size.
|
||||
this.setSize(this.size);
|
||||
|
||||
// Set default transform (including inverted scale for RTL).
|
||||
this.moveTo(new Coordinate(0, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,21 +132,27 @@ export class CommentView implements IRenderedElement {
|
||||
svgRoot: SVGGElement,
|
||||
workspace: WorkspaceSvg,
|
||||
): {
|
||||
topBar: SVGRectElement;
|
||||
topBarGroup: SVGGElement;
|
||||
topBarBackground: SVGRectElement;
|
||||
deleteIcon: SVGImageElement;
|
||||
foldoutIcon: SVGImageElement;
|
||||
textPreview: SVGTextElement;
|
||||
textPreviewNode: Text;
|
||||
} {
|
||||
const topBar = dom.createSvgElement(
|
||||
Svg.RECT,
|
||||
const topBarGroup = dom.createSvgElement(
|
||||
Svg.G,
|
||||
{
|
||||
'class': 'blocklyCommentTopbar',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
},
|
||||
svgRoot,
|
||||
);
|
||||
const topBarBackground = dom.createSvgElement(
|
||||
Svg.RECT,
|
||||
{
|
||||
'class': 'blocklyCommentTopbarBackground',
|
||||
},
|
||||
topBarGroup,
|
||||
);
|
||||
// TODO: Before merging, does this mean to override an individual image,
|
||||
// folks need to replace the whole media folder?
|
||||
const deleteIcon = dom.createSvgElement(
|
||||
@@ -148,7 +161,7 @@ export class CommentView implements IRenderedElement {
|
||||
'class': 'blocklyDeleteIcon',
|
||||
'href': `${workspace.options.pathToMedia}delete-icon.svg`,
|
||||
},
|
||||
svgRoot,
|
||||
topBarGroup,
|
||||
);
|
||||
const foldoutIcon = dom.createSvgElement(
|
||||
Svg.IMAGE,
|
||||
@@ -156,14 +169,14 @@ export class CommentView implements IRenderedElement {
|
||||
'class': 'blocklyFoldoutIcon',
|
||||
'href': `${workspace.options.pathToMedia}arrow-dropdown.svg`,
|
||||
},
|
||||
svgRoot,
|
||||
topBarGroup,
|
||||
);
|
||||
const textPreview = dom.createSvgElement(
|
||||
Svg.TEXT,
|
||||
{
|
||||
'class': 'blocklyCommentPreview blocklyCommentText blocklyText',
|
||||
},
|
||||
svgRoot,
|
||||
topBarGroup,
|
||||
);
|
||||
const textPreviewNode = document.createTextNode('');
|
||||
textPreview.appendChild(textPreviewNode);
|
||||
@@ -184,7 +197,14 @@ export class CommentView implements IRenderedElement {
|
||||
this.onDeleteDown,
|
||||
);
|
||||
|
||||
return {topBar, deleteIcon, foldoutIcon, textPreview, textPreviewNode};
|
||||
return {
|
||||
topBarGroup,
|
||||
topBarBackground,
|
||||
deleteIcon,
|
||||
foldoutIcon,
|
||||
textPreview,
|
||||
textPreviewNode,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,7 +278,7 @@ export class CommentView implements IRenderedElement {
|
||||
* elements to reflect the new size.
|
||||
*/
|
||||
setSize(size: Size) {
|
||||
const topBarSize = this.topBar.getBBox();
|
||||
const topBarSize = this.topBarBackground.getBBox();
|
||||
const deleteSize = this.deleteIcon.getBBox();
|
||||
const foldoutSize = this.foldoutIcon.getBBox();
|
||||
const textPreviewSize = this.textPreview.getBBox();
|
||||
@@ -274,8 +294,7 @@ export class CommentView implements IRenderedElement {
|
||||
this.svgRoot.setAttribute('height', `${size.height}`);
|
||||
this.svgRoot.setAttribute('width', `${size.width}`);
|
||||
|
||||
this.topBar.setAttribute('width', `${size.width}`);
|
||||
|
||||
this.updateTopBarSize(size);
|
||||
this.updateTextAreaSize(size, topBarSize);
|
||||
this.updateDeleteIconPosition(size, topBarSize, deleteSize);
|
||||
this.updateFoldoutIconPosition(topBarSize, foldoutSize);
|
||||
@@ -286,9 +305,7 @@ export class CommentView implements IRenderedElement {
|
||||
deleteSize,
|
||||
resizeSize,
|
||||
);
|
||||
|
||||
this.resizeHandle.setAttribute('x', `${size.width - resizeSize.width}`);
|
||||
this.resizeHandle.setAttribute('y', `${size.height - resizeSize.height}`);
|
||||
this.updateResizeHandlePosition(size, resizeSize);
|
||||
|
||||
this.onSizeChange(oldSize, this.size);
|
||||
}
|
||||
@@ -340,6 +357,11 @@ export class CommentView implements IRenderedElement {
|
||||
return (topBarSize.height - foldoutSize.height) / 2;
|
||||
}
|
||||
|
||||
/** Updates the size of the top bar to reflect the new size. */
|
||||
private updateTopBarSize(size: Size) {
|
||||
this.topBarBackground.setAttribute('width', `${size.width}`);
|
||||
}
|
||||
|
||||
/** Updates the size of the text area elements to reflect the new size. */
|
||||
private updateTextAreaSize(size: Size, topBarSize: Size) {
|
||||
this.foreignObject.setAttribute(
|
||||
@@ -411,6 +433,12 @@ export class CommentView implements IRenderedElement {
|
||||
this.textPreview.setAttribute('width', `${textPreviewWidth}`);
|
||||
}
|
||||
|
||||
/** Updates the position of the resize handle to reflect the new size. */
|
||||
private updateResizeHandlePosition(size: Size, resizeSize: Size) {
|
||||
this.resizeHandle.setAttribute('y', `${size.height - resizeSize.height}`);
|
||||
this.resizeHandle.setAttribute('x', `${size.width - resizeSize.width}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers listeners when the size of the comment changes, either
|
||||
* progrmatically or manually by the user.
|
||||
@@ -750,7 +778,7 @@ css.register(`
|
||||
cursor: se-resize;
|
||||
}
|
||||
|
||||
.blocklyCommentTopbar {
|
||||
.blocklyCommentTopbarBackground {
|
||||
fill: var(--commentBorderColour);
|
||||
height: 24px;
|
||||
}
|
||||
@@ -774,13 +802,11 @@ css.register(`
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.blocklyRTL .blocklyComment {
|
||||
.blocklyRTL .blocklyCommentTopbar {
|
||||
transform: scale(-1, 1);
|
||||
}
|
||||
|
||||
.blocklyRTL .blocklyCommentForeignObject {
|
||||
/* Revert the scale and control RTL using direction instead. */
|
||||
transform: scale(-1, 1);
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
@@ -791,6 +817,7 @@ css.register(`
|
||||
}
|
||||
|
||||
.blocklyRTL .blocklyResizeHandle {
|
||||
transform: scale(-1, 1);
|
||||
cursor: sw-resize;
|
||||
}
|
||||
`);
|
||||
|
||||
@@ -48,7 +48,7 @@ export class WorkspaceComment {
|
||||
* be generated.
|
||||
*/
|
||||
constructor(
|
||||
protected readonly workspace: Workspace,
|
||||
public readonly workspace: Workspace,
|
||||
id?: string,
|
||||
) {
|
||||
this.id = id && !workspace.getCommentById(id) ? id : idGenerator.genUid();
|
||||
|
||||
@@ -39,6 +39,7 @@ export function save(
|
||||
saveIds?: boolean;
|
||||
} = {},
|
||||
): State {
|
||||
const workspace = comment.workspace;
|
||||
const state: State = Object.create(null);
|
||||
|
||||
state.height = comment.getSize().height;
|
||||
@@ -46,8 +47,9 @@ export function save(
|
||||
|
||||
if (saveIds) state.id = comment.id;
|
||||
if (addCoordinates) {
|
||||
state.x = comment.getRelativeToSurfaceXY().x;
|
||||
state.y = comment.getRelativeToSurfaceXY().y;
|
||||
const loc = comment.getRelativeToSurfaceXY();
|
||||
state.x = workspace.RTL ? workspace.getWidth() - loc.x : loc.x;
|
||||
state.y = loc.y;
|
||||
}
|
||||
|
||||
if (comment.getText()) state.text = comment.getText();
|
||||
@@ -76,9 +78,10 @@ export function append(
|
||||
if (state.text !== undefined) comment.setText(state.text);
|
||||
if (state.x !== undefined || state.y !== undefined) {
|
||||
const defaultLoc = comment.getRelativeToSurfaceXY();
|
||||
comment.moveTo(
|
||||
new Coordinate(state.x ?? defaultLoc.x, state.y ?? defaultLoc.y),
|
||||
);
|
||||
let x = state.x ?? defaultLoc.x;
|
||||
x = workspace.RTL ? workspace.getWidth() - x : x;
|
||||
const y = state.y ?? defaultLoc.y;
|
||||
comment.moveTo(new Coordinate(x, y));
|
||||
}
|
||||
if (state.width !== undefined || state.height) {
|
||||
const defaultSize = comment.getSize();
|
||||
|
||||
14
core/xml.ts
14
core/xml.ts
@@ -62,8 +62,11 @@ function saveWorkspaceComment(
|
||||
const elem = utilsXml.createElement('comment');
|
||||
if (!skipId) elem.setAttribute('id', comment.id);
|
||||
|
||||
elem.setAttribute('x', `${comment.getRelativeToSurfaceXY().x}`);
|
||||
elem.setAttribute('y', `${comment.getRelativeToSurfaceXY().y}`);
|
||||
const workspace = comment.workspace;
|
||||
const loc = comment.getRelativeToSurfaceXY();
|
||||
loc.x = workspace.RTL ? workspace.getWidth() - loc.x : loc.x;
|
||||
elem.setAttribute('x', `${loc.x}`);
|
||||
elem.setAttribute('y', `${loc.y}`);
|
||||
elem.setAttribute('w', `${comment.getSize().width}`);
|
||||
elem.setAttribute('h', `${comment.getSize().height}`);
|
||||
|
||||
@@ -503,9 +506,12 @@ function loadWorkspaceComment(
|
||||
|
||||
comment.setText(elem.textContent ?? '');
|
||||
|
||||
const x = parseInt(elem.getAttribute('x') ?? '', 10);
|
||||
let x = parseInt(elem.getAttribute('x') ?? '', 10);
|
||||
const y = parseInt(elem.getAttribute('y') ?? '', 10);
|
||||
if (!isNaN(x) && !isNaN(y)) comment.moveTo(new Coordinate(x, y));
|
||||
if (!isNaN(x) && !isNaN(y)) {
|
||||
x = workspace.RTL ? workspace.getWidth() - x : x;
|
||||
comment.moveTo(new Coordinate(x, y));
|
||||
}
|
||||
|
||||
const w = parseInt(elem.getAttribute('w') ?? '', 10);
|
||||
const h = parseInt(elem.getAttribute('h') ?? '', 10);
|
||||
|
||||
Reference in New Issue
Block a user