Merge pull request #5278 from ishaisagi-hns/image-editor-webpart-enhancements

This commit is contained in:
Hugo Bernier 2024-10-12 18:54:05 -07:00 committed by GitHub
commit 88310656fe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 79 additions and 40 deletions

View File

@ -66,6 +66,7 @@ References to office-ui-fabric-react version 5.x because of SharePoint 2019 Supp
## Contributors
* [Peter Paul Kirschner](https://github.com/petkir)
* [Ishai Sagi] (http://github.com/ishaisagi-hns)
Thanks to [celum](https://www.celum.com/) and [cubido](https://www.cubido.at/) to allow to share this code.
@ -73,6 +74,7 @@ Thanks to [celum](https://www.celum.com/) and [cubido](https://www.cubido.at/) t
Version|Date|Comments
-------|----|--------
1.1.0.0|Sep 09, 2024|Added properties and accessibility
1.0.0.0|Mar 17, 2021|Initial release
## Minimal Path to Awesome

View File

@ -59,11 +59,14 @@ export interface IImageManipulationProps {
editMode?: (mode: boolean) => void;
configSettings: IImageManipulationConfig;
displayMode: DisplayMode;
altText: string;
}
export interface IImageManipulationState {
settingPanel: SettingPanelType;
redosettings: IImageManipulationSettings[];
lockAspectCrop: boolean;
lockAspectResize: boolean;
}
export class ImageManipulation extends React.Component<IImageManipulationProps, IImageManipulationState> {
@ -81,7 +84,9 @@ export class ImageManipulation extends React.Component<IImageManipulationProps,
this.state = {
settingPanel: SettingPanelType.Closed,
redosettings: []
redosettings: [],
lockAspectCrop: true,
lockAspectResize: true
};
this.openPanel = this.openPanel.bind(this);
this.setRotate = this.setRotate.bind(this);
@ -109,6 +114,7 @@ export class ImageManipulation extends React.Component<IImageManipulationProps,
this.img = new Image();
this.img.src = url;
this.img.crossOrigin = 'Anonymous';
this.img.alt = this.props.altText ? this.props.altText : 'Untitled image';
this.img.onload = () => {
this.applySettings();
@ -305,7 +311,7 @@ export class ImageManipulation extends React.Component<IImageManipulationProps,
<canvas className={this.getMaxWidth()}
style={{ display: 'none' }}
ref={this.setManipulateRef}></canvas>
<canvas className={this.getMaxWidth()} ref={this.setCanvasRef} ></canvas>
<canvas className={this.getMaxWidth()} ref={this.setCanvasRef} aria-label={this.props.altText} role='img' >Your browser does not support displaying canvas elements.</canvas>
{this.state.settingPanel === SettingPanelType.Crop && (this.getCropGrid())}
{this.state.settingPanel === SettingPanelType.Resize && (this.getResizeGrid())}
@ -600,17 +606,20 @@ export class ImageManipulation extends React.Component<IImageManipulationProps,
return (<div>
<Checkbox
label={strings.LockAspect}
checked={!isNaN(crop.aspect)}
onChange={() => {
if (isNaN(crop.aspect)) {
this.setCrop(undefined, undefined, undefined, undefined, this.getAspect());
} else {
this.setCrop(undefined, undefined, undefined, undefined, undefined);
}
checked={this.state.lockAspectCrop}
onChange={(e, checked) => {
// Toggle the lockAspect state when checkbox is checked/unchecked
this.setState({ lockAspectCrop: checked }, () => {
// Call the setCrop function with appropriate arguments based on the new state
if (this.state.lockAspectCrop) {
this.setCrop(undefined, undefined, undefined, undefined, this.getAspect());
} else {
this.setCrop(undefined, undefined, undefined, undefined, undefined);
}
});
}}
/>
<TextField
label={strings.SourceX}
value={'' + crop.sx}
@ -640,13 +649,16 @@ export class ImageManipulation extends React.Component<IImageManipulationProps,
<Checkbox
label={strings.LockAspect}
checked={!isNaN(resize.aspect)}
checked={this.state.lockAspectResize}
onChange={() => {
if (isNaN(resize.aspect)) {
this.setResize(undefined, undefined, this.getAspect());
} else {
this.setResize(undefined, undefined, undefined);
}
this.setState({ lockAspectResize: !this.state.lockAspectResize }, () => {
if (isNaN(resize.aspect)) {
this.setResize(undefined, undefined, this.getAspect());
} else {
this.setResize(undefined, undefined, undefined);
}
})
}}

View File

@ -12,12 +12,13 @@
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": { "default": "Other" },
"title": { "default": "react-image-editor" },
"description": { "default": "react-image-editor description" },
"title": { "default": "Advanced Image Editor" },
"description": { "default": "Add an image to the page, resize and edit the image." },
"officeFabricIconFontName": "Page",
"properties": {
"title": "react-image-editor Sample",
"showTitle":true,
"title": "Advanced Image Editor",
"showTitle":false,
"showEditIcon":false,
"settings":[],
"url":""
}

View File

@ -4,6 +4,8 @@ import { Version } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneLabel,
PropertyPaneTextField,
PropertyPaneToggle
} from '@microsoft/sp-webpart-base';
@ -28,6 +30,10 @@ export default class ReactImageEditorWebPart extends BaseClientSideWebPart<IReac
title: this.properties.title,
url: this.properties.url,
settings: this.properties.settings,
showEditIcon:this.properties.showEditIcon,
altText:this.properties.altText,
updateTitleProperty: (value: string) => { this.properties.title = value; },
updateUrlProperty: (value: string) => {
@ -67,9 +73,16 @@ export default class ReactImageEditorWebPart extends BaseClientSideWebPart<IReac
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('altText',{label:strings.AltTextFieldLabel}),
PropertyPaneToggle('showTitle', {
label: strings.ShowTitleFieldLabel
})
,
PropertyPaneToggle('showEditIcon', {
label: strings.ShowEditIconFieldLabel
}),
PropertyPaneLabel('urlInfo',{text:`The selected image is at ${this.properties.url?this.properties.url:'Not yet selected'} `})
]
}
]

View File

@ -9,9 +9,11 @@ import { ImageManipulation, IImageManipulationSettings } from '../../../componen
export interface IReactImageEditorBaseProps {
showTitle: boolean;
showEditIcon: boolean;
title: string;
url?: string;
settings?: IImageManipulationSettings[];
altText?: string;
}
@ -21,6 +23,7 @@ export interface IReactImageEditorProps extends IReactImageEditorBaseProps {
updateTitleProperty: (value: string) => void;
updateUrlProperty: (value: string) => void;
updateManipulationSettingsProperty: (value: IImageManipulationSettings[]) => void;
}
export interface IReactImageEditorState {
@ -46,14 +49,16 @@ export default class ReactImageEditor extends React.Component<IReactImageEditorP
return (
<div className={styles.reactImageEditor}>
<WebPartTitle displayMode={this.props.displayMode}
title={this.props.title}
updateProperty={this.props.updateTitleProperty} />
{(isFilePickerOpen || isConfigured) && Environment.type !== EnvironmentType.Local &&
{this.props.showTitle &&
<WebPartTitle displayMode={this.props.displayMode}
title={this.props.title}
updateProperty={this.props.updateTitleProperty} />
}
{(isFilePickerOpen || (isConfigured && this.props.displayMode === DisplayMode.Edit)) && Environment.type !== EnvironmentType.Local &&
<FilePicker
isPanelOpen={isFilePickerOpen}
accepts={['.gif', '.jpg', '.jpeg', '.png']}
buttonIcon='FileImage'
buttonIcon={'FileImage'}
onSave={(filePickerResult: IFilePickerResult) => {
this.setState({ isFilePickerOpen: false }, () => this._onUrlChanged(filePickerResult.fileAbsoluteUrl));
}}
@ -65,6 +70,7 @@ export default class ReactImageEditor extends React.Component<IReactImageEditorP
}}
context={this.props.context}
/>}
{!isConfigured ? (<Placeholder iconName='Edit'
@ -73,16 +79,16 @@ export default class ReactImageEditor extends React.Component<IReactImageEditorP
buttonLabel='Configure'
onConfigure={this._onConfigure} />) :
(
<ImageManipulation
settings={this.props.settings}
configSettings={{
rotateButtons: [-90, -45, -30, 0, 30, 45, 90]
}
}
displayMode={this.props.displayMode}
settingsChanged={this._onSettingsChanged}
src={this.props.url}
/>
<ImageManipulation
settings={this.props.settings}
configSettings={{
rotateButtons: [-90, -45, -30, 0, 30, 45, 90]
}
}
displayMode={this.props.displayMode}
settingsChanged={this._onSettingsChanged}
src={this.props.url} altText={this.props.altText}
/>
)}
</div >
@ -95,7 +101,7 @@ export default class ReactImageEditor extends React.Component<IReactImageEditorP
this._onUrlChanged(
'https://media.gettyimages.com/photos/'
+ 'whitewater-paddlers-descend-vertical-waterfall-in-kayak-picture-id1256321293?s=2048x2048'
);
);
});
} else {
this.setState({ isFilePickerOpen: true });

View File

@ -1,7 +1,10 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"ShowTitleFieldLabel": "Show webpart title"
"PropertyPaneDescription": "",
"BasicGroupName": "Web part configuration",
"ShowTitleFieldLabel": "Show webpart title",
"ShowEditIconFieldLabel": "Show edit icon",
"AltTextFieldLabel":"Alt Text"
}
});

View File

@ -2,6 +2,8 @@ declare interface IReactImageEditorWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
ShowTitleFieldLabel: string;
ShowEditIconFieldLabel: string;
AltTextFieldLabel: string;
}
declare module 'ReactImageEditorWebPartStrings' {