Skip to content

Commit

Permalink
fix conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
juliaroldi committed May 17, 2022
2 parents 03f92b0 + 18b361e commit 2958916
Show file tree
Hide file tree
Showing 36 changed files with 1,441 additions and 158 deletions.
8 changes: 1 addition & 7 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
name: Build and Test
on:
push:
branches-ignore:
- master
pull_request:
branches-ignore:
- master
on: [push, pull_request]

jobs:
build:
Expand Down
41 changes: 41 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.6 BLOCK -->

## Security

Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).

If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](<https://docs.microsoft.com/previous-versions/tn-archive/cc751383(v=technet.10)>), please report it to us as described below.

## Reporting Security Issues

**Please do not report security vulnerabilities through public GitHub issues.**

Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).

If you prefer to submit without logging in, send email to [[email protected]](mailto:[email protected]). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/msrc/pgp-key-msrc).

You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).

Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:

- Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
- Full paths of source file(s) related to the manifestation of the issue
- The location of the affected source code (tag/branch/commit or direct URL)
- Any special configuration required to reproduce the issue
- Step-by-step instructions to reproduce the issue
- Proof-of-concept or exploit code (if possible)
- Impact of the issue, including how an attacker might exploit the issue

This information will help us triage your report more quickly.

If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.

## Preferred Languages

We prefer all communications to be in English.

## Policy

Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/msrc/cvd).

<!-- END MICROSOFT SECURITY.MD BLOCK -->
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "roosterjs",
"version": "8.22.0",
"version": "8.22.1",
"description": "Framework-independent javascript editor",
"repository": {
"type": "git",
Expand Down
15 changes: 14 additions & 1 deletion packages/roosterjs-editor-api/lib/format/createLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ function applyLinkPrefix(url: string): string {
* When protocol is not specified, a best matched protocol will be predicted.
* @param altText Optional alt text of the link, will be shown when hover on the link
* @param displayText Optional display text for the link.
* @param target Optional display target for the link ("_blank"|"_self"|"_parent"|"_top"|"{framename}")
* If specified, the display text of link will be replaced with this text.
* If not specified and there wasn't a link, the link url will be used as display text.
*/
export default function createLink(
editor: IEditor,
link: string,
altText?: string,
displayText?: string
displayText?: string,
target?: string
) {
editor.focus();
let url = (checkXss(link) || '').trim();
Expand Down Expand Up @@ -96,6 +98,9 @@ export default function createLink(
if (altText && anchor) {
anchor.title = altText;
}
if (anchor) {
updateAnchorTarget(anchor, target);
}
return anchor;
}, ChangeSource.CreateLink);
}
Expand All @@ -111,6 +116,14 @@ function updateAnchorDisplayText(anchor: HTMLAnchorElement, displayText: string)
}
}

function updateAnchorTarget(anchor: HTMLAnchorElement, target?: string) {
if (target) {
anchor.target = target;
} else if (!target && anchor.getAttribute('target')) {
anchor.removeAttribute('target');
}
}

function checkXss(link: string): string {
const sanitizer = new HtmlSanitizer();
const a = document.createElement('a');
Expand Down
35 changes: 28 additions & 7 deletions packages/roosterjs-editor-api/lib/format/insertImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,53 @@ import { readFile } from 'roosterjs-editor-dom';
* @param editor The editor instance
* @param imageFile The image file. There are at least 3 ways to obtain the file object:
* From local file, from clipboard data, from drag-and-drop
* @param attributes Optional image element attributes
*/
export default function insertImage(editor: IEditor, imageFile: File): void;
export default function insertImage(
editor: IEditor,
imageFile: File,
attributes?: Record<string, string>
): void;

/**
* Insert an image to editor at current selection
* @param editor The editor instance
* @param imageFile The image link.
* @param url The image link
* @param attributes Optional image element attributes
*/
export default function insertImage(editor: IEditor, url: string): void;
export default function insertImage(
editor: IEditor,
url: string,
attributes?: Record<string, string>
): void;

export default function insertImage(editor: IEditor, imageFile: File | string): void {
export default function insertImage(
editor: IEditor,
imageFile: File | string,
attributes?: Record<string, string>
): void {
if (typeof imageFile == 'string') {
insertImageWithSrc(editor, imageFile);
insertImageWithSrc(editor, imageFile, attributes);
} else {
readFile(imageFile, dataUrl => {
if (dataUrl && !editor.isDisposed()) {
insertImageWithSrc(editor, dataUrl);
insertImageWithSrc(editor, dataUrl, attributes);
}
});
}
}

function insertImageWithSrc(editor: IEditor, src: string) {
function insertImageWithSrc(editor: IEditor, src: string, attributes?: Record<string, string>) {
editor.addUndoSnapshot(() => {
const image = editor.getDocument().createElement('img');
image.src = src;

if (attributes) {
Object.keys(attributes).forEach(attribute =>
image.setAttribute(attribute, attributes[attribute])
);
}

image.style.maxWidth = '100%';
editor.insertNode(image);
}, ChangeSource.Format);
Expand Down
9 changes: 9 additions & 0 deletions packages/roosterjs-editor-api/test/format/createLinkTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ describe('createLink()', () => {
expect(link.outerHTML).toBe('<a href="http://www.example.com">this is my link</a>');
});

it('sets target attribute in the link', () => {
// Act
createLink(editor, 'www.example.com', undefined, undefined, '_self');

// Assert
let link = document.getElementsByTagName('a')[0];
expect(link.target).toBe('_self');
});

it('Issue when selection is under another tag', () => {
editor.setContent(
'<div><span id="span1" style="box-sizing:border-box;color:rgba(0, 0, 0, 0.9);background-color:rgb(255, 255, 255);font-family:Calibri, Helvetica, sans-serif;display:inline !important">Hello<span style="box-sizing:border-box">&nbsp;</span></span><b style="box-sizing:border-box;color:rgba(0, 0, 0, 0.9);background-color:rgb(255, 255, 255);font-family:Calibri, Helvetica, sans-serif" id="span2">world<span style="box-sizing:border-box">&nbsp;</span></b><span style="box-sizing:border-box;color:rgba(0, 0, 0, 0.9);background-color:rgb(255, 255, 255);margin:0px;font-family:Calibri, Helvetica, sans-serif">🙂</span><span style="box-sizing:border-box;color:rgba(0, 0, 0, 0.9);background-color:rgb(255, 255, 255);font-family:Calibri, Helvetica, sans-serif;display:inline !important">&nbsp;this is a test</span><br></div><!--{"start":[0,0,0,0],"end":[0,0,0,0]}-->'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,27 @@ export default class SelectionBlockScoper implements TraversingScoper {
position: NodePosition | Range,
private startFrom: ContentPosition | CompatibleContentPosition
) {
position = safeInstanceOf(position, 'Range') ? Position.getStart(position) : position;
this.position = position.normalize();
this.block = getBlockElementAtNode(this.rootNode, this.position.node);
// Debugging info, will be removed later
let isPosition = false;

if (safeInstanceOf(position, 'Range')) {
position = Position.getStart(position);
} else {
isPosition = true;
}

try {
this.position = position.normalize();
this.block = getBlockElementAtNode(this.rootNode, this.position.node);
} catch (e) {
throw new Error(
`${
(e as any)?.message
}; isPosition: ${isPosition}; actual type: ${typeof position}; String name: ${
typeof position?.toString === 'function' ? position.toString() : 'No toString()'
}`
);
}
}

/**
Expand Down
10 changes: 10 additions & 0 deletions packages/roosterjs-editor-dom/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,13 @@ export { default as setStyles } from './style/setStyles';
export { default as adjustInsertPosition } from './edit/adjustInsertPosition';
export { default as deleteSelectedContent } from './edit/deleteSelectedContent';
export { default as getTextContent } from './edit/getTextContent';

export { default as validate } from './metadata/validate';
export {
createNumberDefinition,
createBooleanDefinition,
createStringDefinition,
createArrayDefinition,
createObjectDefinition,
} from './metadata/definitionCreators';
export { getMetadata, setMetadata, removeMetadata } from './metadata/metadata';
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { getNextLeafSibling } from '../utils/getLeafSibling';
import { NodePosition, NodeType, PositionType } from 'roosterjs-editor-types';
import { splitBalancedNodeRange } from '../utils/splitParentNode';

const STYLET_AGS = 'SPAN,B,I,U,EM,STRONG,STRIKE,S,SMALL'.split(',');
const STYLET_AGS = 'SPAN,B,I,U,EM,STRONG,STRIKE,S,SMALL,SUP,SUB'.split(',');

/**
* Apply style using a styler function to the given container node in the given range
Expand Down
120 changes: 120 additions & 0 deletions packages/roosterjs-editor-dom/lib/metadata/definitionCreators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import {
Definition,
DefinitionType,
NumberDefinition,
ArrayDefinition,
BooleanDefinition,
StringDefinition,
ObjectDefinition,
ObjectPropertyDefinition,
} from 'roosterjs-editor-types';

/**
* Create a number definition
* @param isOptional Whether this property is optional
* @param value Optional value of the number
* @param minValue Optional minimum value
* @param maxValue Optional maximum value
* @param allowNull Allow the property to be null
* @returns The number definition object
*/
export function createNumberDefinition(
isOptional?: boolean,
value?: number,
minValue?: number,
maxValue?: number,
allowNull?: boolean
): NumberDefinition {
return {
type: DefinitionType.Number,
isOptional,
value,
maxValue,
minValue,
allowNull,
};
}

/**
* Create a boolean definition
* @param isOptional Whether this property is optional
* @param value Optional expected boolean value
* @param allowNull Allow the property to be null
* @returns The boolean definition object
*/
export function createBooleanDefinition(
isOptional?: boolean,
value?: boolean,
allowNull?: boolean
): BooleanDefinition {
return {
type: DefinitionType.Boolean,
isOptional,
value,
allowNull,
};
}

/**
* Create a string definition
* @param isOptional Whether this property is optional
* @param value Optional expected string value
* @param allowNull Allow the property to be null
* @returns The string definition object
*/
export function createStringDefinition(
isOptional?: boolean,
value?: string,
allowNull?: boolean
): StringDefinition {
return {
type: DefinitionType.String,
isOptional,
value,
allowNull,
};
}

/**
* Create an array definition
* @param itemDef Definition of each item of the related array
* @param isOptional Whether this property is optional
* @param allowNull Allow the property to be null
* @returns The array definition object
*/
export function createArrayDefinition<T>(
itemDef: Definition<T>,
isOptional?: boolean,
minLength?: number,
maxLength?: number,
allowNull?: boolean
): ArrayDefinition<T[]> {
return {
type: DefinitionType.Array,
isOptional,
itemDef,
minLength,
maxLength,
allowNull,
};
}

/**
* Create an object definition
* @param propertyDef Definition of each property of the related object
* @param isOptional Whether this property is optional
* @param allowNull Allow the property to be null
* @returns The object definition object
*/
export function createObjectDefinition<T extends Object>(
propertyDef: ObjectPropertyDefinition<T>,
isOptional?: boolean,
allowNull?: boolean
): ObjectDefinition<T> {
return {
type: DefinitionType.Object,
isOptional,
propertyDef,
allowNull,
};
}
Loading

0 comments on commit 2958916

Please sign in to comment.