-
Notifications
You must be signed in to change notification settings - Fork 387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix/add new tab option rich text #1668
base: dev
Are you sure you want to change the base?
Changes from all commits
dad80ca
73f83b8
c5d0f33
0ffd2fb
a5709ae
a22e693
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ import * as strings from 'ControlStrings'; | |
import 'react-quill/dist/quill.snow.css'; | ||
import RichTextPropertyPane from './RichTextPropertyPane'; | ||
import ReactQuill, { Quill as ReactQuillInstance } from 'react-quill'; | ||
import type { Quill } from 'quill'; | ||
import { Quill } from 'quill'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you remove |
||
import styles from './RichText.module.scss'; | ||
import { IRichTextProps, IRichTextState } from './RichText.types'; | ||
import { Guid } from '@microsoft/sp-core-library'; | ||
|
@@ -89,6 +89,15 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
text: strings.ListNumbered, | ||
data: { icon: 'NumberedList' } | ||
}]; | ||
private ddLinkTargetOpts = [{ | ||
key: '_self', | ||
id: 'same', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd just use the same |
||
text: strings.SameTab | ||
}, { | ||
key: '_blank', | ||
id: 'new', | ||
text: strings.NewTab | ||
}]; | ||
|
||
/** | ||
* Sets default properties | ||
|
@@ -126,6 +135,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
insertImageUrl: undefined, | ||
selectedText: undefined, | ||
selectedUrl: undefined, | ||
dropdownLinkTarget: '_self', | ||
wrapperTop: 0 | ||
}; | ||
|
||
|
@@ -394,6 +404,15 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
} | ||
}} /> | ||
|
||
<Dropdown | ||
id="DropDownLinkTarget" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, do not provide ids for the elements. |
||
label='Open link in' | ||
onRenderCaretDown={() => <Icon className={styles.toolbarSubmenuCaretLT} iconName="CaretDownSolid8" />} | ||
selectedKey={this.state.dropdownLinkTarget || '_self'} | ||
options={this.ddLinkTargetOpts} | ||
onChange={this.onChangeLinkTarget} | ||
/> | ||
|
||
<DialogFooter className={styles.actions}> | ||
<div className={`ms-Dialog-actionsRight ${styles.actionsRight}`}> | ||
{ | ||
|
@@ -513,6 +532,17 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
'super']; | ||
ReactQuillInstance.register(sizeClass, true); | ||
|
||
const CusLink = ReactQuillInstance.import('formats/link'); | ||
class TLink extends CusLink { | ||
static create(value) { | ||
const node = super.create(value); | ||
node.setAttribute('href', value.href); | ||
node.setAttribute('target', value.target); | ||
return node; | ||
} | ||
} | ||
|
||
ReactQuillInstance.register(TLink, true); | ||
return ( | ||
<div ref={(ref) => { this._wrapperRef = ref; }} className={css(styles.richtext && this.state.editing ? 'ql-active' : null, this.props.className || null) || null}> | ||
{renderLabel} | ||
|
@@ -690,6 +720,12 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
this.applyFormat("align", newAlignValue); | ||
} | ||
|
||
private onChangeLinkTarget = (_event: React.FormEvent<HTMLDivElement>, item?: IDropdownOption, _index?: number): void => { | ||
this.setState({ | ||
dropdownLinkTarget: item.key.toString() | ||
}) | ||
} | ||
|
||
private onChangeList = (_event: React.FormEvent<HTMLDivElement>, item?: IDropdownOption, _index?: number): void => { | ||
// if we're already in list mode, toggle off | ||
const key = item.key; | ||
|
@@ -705,6 +741,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
const range = quill.getSelection(); | ||
|
||
let linkText = this.state.selectedText; | ||
let dropdownLinkTarget = '_self'; | ||
if (this.state.selectedUrl !== undefined && this.state.selectedText === "") { | ||
const { text } = this.state; | ||
const urlStartIndex = text.indexOf(this.state.selectedUrl); | ||
|
@@ -718,16 +755,32 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
const linkStart = editorText.indexOf(linkText); | ||
range.index = linkStart; | ||
range.length = linkText.length; | ||
|
||
dropdownLinkTarget = this.calculateLinkTargetBasedOnSelectedText(text.substring(urlStartIndex, endTextIndex)); | ||
} | ||
|
||
|
||
|
||
this.setState({ | ||
hideDialog: false, | ||
insertUrlText: linkText, | ||
insertUrl: this.state.selectedUrl, | ||
dropdownLinkTarget: dropdownLinkTarget, | ||
selectedRange: range | ||
}); | ||
} | ||
|
||
/** | ||
* Get target value on text selection | ||
*/ | ||
private calculateLinkTargetBasedOnSelectedText = (selectedText: string): string => { | ||
if (selectedText.includes('_blank')) { | ||
return '_blank'; // Open in a new tab for links containing "_blank" | ||
} else { | ||
return '_self'; // Open in the same tab for other links | ||
} | ||
} | ||
|
||
/** | ||
* Hides the insert link dialog | ||
*/ | ||
|
@@ -790,15 +843,21 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
if (cursorPosition > -1) { | ||
const textToInsert: string = (this.state.insertUrlText !== undefined && this.state.insertUrlText !== "") ? this.state.insertUrlText : this.state.insertUrl; | ||
const urlToInsert: string = this.state.insertUrl; | ||
const targetToInsert: string = this.state.dropdownLinkTarget; | ||
quill.insertText(cursorPosition, textToInsert); | ||
quill.setSelection(cursorPosition, textToInsert.length); | ||
quill.formatText(cursorPosition, textToInsert.length, 'link', urlToInsert); | ||
quill.formatText(cursorPosition, textToInsert.length, 'link', { | ||
href: urlToInsert, | ||
target: targetToInsert, | ||
}); | ||
} | ||
|
||
|
||
this.setState({ | ||
hideDialog: true, | ||
insertUrl: undefined, | ||
insertUrlText: undefined | ||
insertUrlText: undefined, | ||
dropdownLinkTarget: '_self' | ||
}); | ||
} | ||
|
||
|
@@ -875,7 +934,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
const formats = quill.getFormat(range); | ||
|
||
// Get the currently selected url | ||
const selectedUrl = formats.link ? formats.link : undefined; | ||
const selectedUrl = formats.link ? formats.link : undefined; | ||
|
||
this.setState({ | ||
selectedText: selectedText, | ||
|
@@ -1001,6 +1060,7 @@ export class RichText extends React.Component<IRichTextProps, IRichTextState> { | |
if (label) { | ||
return ( | ||
<Label htmlFor={this._richTextId}> | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please, remove this empty line |
||
{label} | ||
</Label> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -178,4 +178,6 @@ export interface IRichTextState { | |
text: string; | ||
|
||
wrapperTop: number; | ||
|
||
dropdownLinkTarget: string; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need this non-standard caret style for the dropdown?
Why don't just use a default one?