Skip to content

Commit 9388daa

Browse files
JiuqingSongjuliaroldiBryanValverdeU
authored
Version bump to 9.40.0 (#3183)
* support RTL (#3177) * Update ContextMenuProvider to accept event parameter and adjust related tests (#3175) * refactor: remove deprecated features and clean up related code in CachePlugin and CopyPastePlugin (#3178) * Add `test:fast` for faster unit test runs (#3179) * refactor: optimize karma configuration for improved performance * feat: add fast karma configuration and update package.json for debugging * refactor: streamline karma plugin declaration and update test scripts for clarity * refactor: update test commands to use fast karma configuration * Add support for retaining formats when splitting paragraphs on Enter/Delete/Backspace keypress (#3180) * refactor: optimize karma configuration for improved performance * feat: add fast karma configuration and update package.json for debugging * refactor: streamline karma plugin declaration and update test scripts for clarity * Add support for retaining formats when splitting paragraphs on Enter key press - Introduced `formatsToKeep` option in `EditOptions` to specify which formats to retain. - Updated `keyboardEnter`, `handleEnterOnParagraph`, and `splitParagraph` functions to handle the new formats. - Enhanced tests to verify the correct behavior of format retention during paragraph splits. * Remove unused import for handleEnterOnParagraph in keyboardEnterTest * Remove stray backtick from splitParagraph function * refactor: update test commands to use fast karma configuration * feat: implement class format handling and preserve formatting on paragraph split * feat: rename formatsToKeep to formatsToPreserveOnMerge and update related functionality * test: update spies in keyboardDelete tests and fix format property in preserveParagraphFormat tests * Support rowSpan equal to 0 (#3181) * fix: handle zero colSpan and rowSpan in tableProcessor to ensure proper cell creation * fix: correct colSpan condition in tableProcessor for accurate cell processing * feat: add spanUntilNextSection support in table cell processing and handling * refactor: remove spanUntilNextSection from table cell handling and related tests * refactor: simplify rowSpan handling and improve tableProcessor tests for edge cases * Remove unneeded changes * Remove * RoosterJs 9.40.0 --------- Co-authored-by: Julia Roldi <[email protected]> Co-authored-by: Bryan Valverde U <[email protected]>
1 parent 7f7ba78 commit 9388daa

File tree

47 files changed

+2500
-200
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+2500
-200
lines changed

demo/scripts/controlsV2/mainPane/MainPane.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
530530
editPluginOptions,
531531
} = this.state.initState;
532532

533+
editPluginOptions.formatsToPreserveOnMerge = ['className'];
533534
return [
534535
pluginList.autoFormat && new AutoFormatPlugin(autoFormatOptions),
535536
pluginList.edit && new EditPlugin(editPluginOptions),
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { ContentModelFormatBase, FormatApplier, FormatParser } from 'roosterjs-content-model-types';
2+
3+
interface ClassFormat extends ContentModelFormatBase {
4+
className?: string;
5+
}
6+
7+
interface ClassFormatHandler {
8+
/**
9+
* Parse format from the given HTML element and default style
10+
*/
11+
parse: FormatParser<ClassFormat>;
12+
13+
/**
14+
* Apply format to the given HTML element
15+
*/
16+
apply: FormatApplier<ClassFormat>;
17+
}
18+
19+
export const classFormatHandler: ClassFormatHandler = {
20+
parse: (format, element) => {
21+
const className = element.className;
22+
if (className) {
23+
format.className = element.className;
24+
}
25+
},
26+
apply: (format, element) => {
27+
// Custom formatting logic for class elements
28+
const className = format.className;
29+
if (className) {
30+
element.className = className;
31+
}
32+
},
33+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import { classFormatHandler } from './classFormatHandlet';
12
import { demoUndeletableAnchorParser } from './demoUndeletableAnchorParser';
23
import { DomToModelOption } from 'roosterjs-content-model-types';
34

45
export const defaultDomToModelOption: DomToModelOption = {
56
additionalFormatParsers: {
67
link: [demoUndeletableAnchorParser],
8+
block: [classFormatHandler.parse],
79
},
810
processNonVisibleElements: true,
911
};

demo/scripts/controlsV2/options/defaultModelToDomOption.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import { classFormatHandler } from './classFormatHandlet';
12
import { ModelToDomOption } from 'roosterjs-content-model-types';
23

34
export const defaultModelToDomOption: ModelToDomOption = {
5+
additionalFormatAppliers: {
6+
block: [classFormatHandler.apply],
7+
},
48
defaultContentModelFormatOverride: {
59
p: {
610
marginTop: '0',

demo/scripts/controlsV2/sidePane/MarkdownPane/MarkdownPane.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ export default class MarkdownPane extends React.Component<
1616
private emptyLinePreserve = React.createRef<HTMLInputElement>();
1717
private emptyLineRemove = React.createRef<HTMLInputElement>();
1818
private emptyLineMerge = React.createRef<HTMLInputElement>();
19+
private isRTL = React.createRef<HTMLInputElement>();
1920

2021
constructor(props: MarkdownPaneProps) {
2122
super(props);
22-
2323
this.state = { emptyLine: 'merge' };
2424
}
2525

@@ -32,6 +32,7 @@ export default class MarkdownPane extends React.Component<
3232
: this.emptyLineRemove.current.checked
3333
? 'remove'
3434
: 'merge',
35+
direction: this.isRTL.current.checked ? 'rtl' : 'ltr',
3536
});
3637

3738
model.blocks = markdownModel.blocks;
@@ -115,6 +116,8 @@ export default class MarkdownPane extends React.Component<
115116
onClick={this.onEmptyLineChange}
116117
/>{' '}
117118
<label htmlFor="emptyLineMerge">Merge</label>
119+
<input type="checkbox" name="RTL" id="isRTL" ref={this.isRTL} />{' '}
120+
<label htmlFor="isRTL">RTL</label>
118121
</div>
119122
<textarea
120123
className={styles.textArea}

karma.fast.conf.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
const argv = require('minimist')(process.argv.slice(2));
2+
const components = argv.components !== true && argv.components;
3+
const runCoverage = typeof argv.coverage !== 'undefined';
4+
const runFirefox = typeof argv.firefox !== 'undefined';
5+
const runChrome = typeof argv.chrome !== 'undefined';
6+
7+
const rootPath = __dirname;
8+
9+
module.exports = function (config) {
10+
const plugins = ['karma-webpack', 'karma-jasmine', 'karma-sourcemap-loader'];
11+
const launcher = [];
12+
13+
if (runCoverage) {
14+
plugins.push('karma-coverage-istanbul-reporter');
15+
}
16+
17+
if (runChrome) {
18+
plugins.push('karma-chrome-launcher');
19+
launcher.push('Chrome');
20+
}
21+
22+
if (runFirefox) {
23+
plugins.push('karma-firefox-launcher');
24+
launcher.push('Firefox');
25+
}
26+
27+
const tsConfig = {
28+
compilerOptions: {
29+
rootDir: rootPath,
30+
declaration: false,
31+
strict: false,
32+
downlevelIteration: true,
33+
transpileOnly: true, // Faster compilation - skip type checking
34+
paths: {
35+
'*': ['*', rootPath + '/packages/*'],
36+
},
37+
},
38+
transpileOnly: true, // Enable faster transpilation
39+
};
40+
41+
const rules = runCoverage
42+
? [
43+
{
44+
test: /lib(\\|\/).*\.ts$/,
45+
use: [
46+
{ loader: '@jsdevtools/coverage-istanbul-loader' },
47+
{
48+
loader: 'ts-loader',
49+
options: tsConfig,
50+
},
51+
],
52+
},
53+
{
54+
test: /test(\\|\/).*\.ts$/,
55+
loader: 'ts-loader',
56+
options: tsConfig,
57+
},
58+
]
59+
: [
60+
{
61+
test: /\.ts$/,
62+
loader: 'ts-loader',
63+
options: tsConfig,
64+
},
65+
];
66+
67+
const settings = {
68+
basePath: '.',
69+
plugins,
70+
client: {
71+
components: components,
72+
clearContext: false,
73+
captureConsole: true,
74+
},
75+
browsers: launcher,
76+
files: ['tools/karma.test.all.js'],
77+
frameworks: ['jasmine'],
78+
preprocessors: {
79+
'tools/karma.test.all.js': ['webpack', 'sourcemap'],
80+
},
81+
port: 9876,
82+
colors: true,
83+
logLevel: config.LOG_INFO,
84+
autoWatch: true,
85+
autoWatchBatchDelay: 300, // Batch file changes for better performance
86+
87+
// to avoid DISCONNECTED messages
88+
browserDisconnectTimeout: 10000, // default 2000
89+
browserDisconnectTolerance: 1, // default 0
90+
browserNoActivityTimeout: 60000, //default 10000
91+
browserConsoleLogOptions: {
92+
level: 'log',
93+
format: '%b %T: %m',
94+
terminal: true,
95+
},
96+
97+
singleRun: true,
98+
captureTimeout: 60000,
99+
100+
webpack: {
101+
mode: 'development',
102+
devtool: 'eval-source-map', // Faster than inline-source-map
103+
module: {
104+
rules,
105+
},
106+
resolve: {
107+
extensions: ['.ts', '.tsx', '.js'],
108+
modules: ['./packages', './node_modules'],
109+
},
110+
// Workaround karma-webpack issue https://github.com/ryanclark/karma-webpack/issues/493
111+
// Got this solution from https://github.com/ryanclark/karma-webpack/issues/493#issuecomment-780411348
112+
optimization: {
113+
splitChunks: false,
114+
removeAvailableModules: false, // Performance optimization
115+
removeEmptyChunks: false, // Performance optimization
116+
},
117+
// Add filesystem caching for better performance
118+
cache: {
119+
type: 'filesystem',
120+
cacheDirectory: require('path').join(rootPath, 'node_modules/.cache/webpack'),
121+
},
122+
stats: 'errors-warnings', // Reduce console output
123+
},
124+
125+
// Concurrency level
126+
// how many browser should be started simultaneous
127+
concurrency: Infinity,
128+
};
129+
130+
if (runCoverage) {
131+
settings.reporters = ['coverage-istanbul'];
132+
settings.coverageIstanbulReporter = {
133+
reports: ['html', 'lcovonly', 'text-summary'],
134+
dir: './dist/deploy/coverage',
135+
};
136+
}
137+
138+
config.set(settings);
139+
};

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@
2727
"test": "node tools/build.js normalize & karma start --chrome",
2828
"test:chrome": "node tools/build.js normalize & karma start --chrome",
2929
"test:firefox": "node tools/build.js normalize & karma start --firefox",
30-
"test:debug": "node tools/build.js normalize & karma start --no-single-run --chrome",
31-
"test:debug-firefox": "node tools/build.js normalize & karma start --no-single-run --firefox",
30+
"test:debug": "node tools/build.js normalize & karma start karma.fast.conf.js --no-single-run --chrome",
31+
"test:fast": "node tools/build.js normalize & karma start karma.fast.conf.js --chrome",
32+
"test:debug-firefox": "node tools/build.js normalize & karma start karma.fast.conf.js --no-single-run --firefox",
3233
"test:coverage": "node tools/build.js normalize & karma start --coverage --firefox --chrome",
3334
"publish": "node tools/build.js clean normalize buildcommonjs buildamd buildmjs dts pack packprod builddemo builddoc publish"
3435
},

packages/roosterjs-content-model-core/lib/corePlugin/cache/CachePlugin.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@ class CachePlugin implements PluginWithState<CachePluginState> {
2727
constructor(option: EditorOptions, contentDiv: HTMLDivElement) {
2828
this.state = {
2929
domIndexer: new DomIndexerImpl(
30-
option.experimentalFeatures &&
31-
option.experimentalFeatures.indexOf('PersistCache') >= 0,
3230
option.experimentalFeatures &&
3331
option.experimentalFeatures.indexOf(
3432
'KeepSelectionMarkerWhenEnteringTextNode'

packages/roosterjs-content-model-core/lib/corePlugin/cache/domIndexerImpl.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ function unindex(node: Partial<IndexedSegmentNode>) {
156156
* Implementation of DomIndexer
157157
*/
158158
export class DomIndexerImpl implements DomIndexer {
159-
constructor(
160-
private readonly persistCache?: boolean,
161-
private readonly keepSelectionMarkerWhenEnteringTextNode?: boolean
162-
) {}
159+
constructor(private readonly keepSelectionMarkerWhenEnteringTextNode?: boolean) {}
163160

164161
onSegment(segmentNode: Node, paragraph: ContentModelParagraph, segment: ContentModelSegment[]) {
165162
const indexedText = segmentNode as IndexedSegmentNode;
@@ -349,10 +346,6 @@ export class DomIndexerImpl implements DomIndexer {
349346
}
350347

351348
reconcileChildList(addedNodes: ArrayLike<Node>, removedNodes: ArrayLike<Node>): boolean {
352-
if (!this.persistCache) {
353-
return false;
354-
}
355-
356349
let canHandle = true;
357350
const context: ReconcileChildListContext = {
358351
segIndex: -1,
@@ -554,10 +547,6 @@ export class DomIndexerImpl implements DomIndexer {
554547
}
555548

556549
this.onSegment(textNode, paragraph, textSegments);
557-
558-
if (!this.persistCache) {
559-
delete paragraph.cachedElement;
560-
}
561550
} else if (first?.segmentType == 'Entity' && first == last) {
562551
const wrapper = first.wrapper;
563552
const index = paragraph.segments.indexOf(first);

packages/roosterjs-content-model-core/lib/corePlugin/contextMenu/ContextMenuPlugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class ContextMenuPlugin implements PluginWithState<ContextMenuPluginState> {
8787

8888
if (targetNode) {
8989
this.state.contextMenuProviders.forEach(provider => {
90-
const items = provider.getContextMenuItems(targetNode) ?? [];
90+
const items = provider.getContextMenuItems(targetNode, mouseEvent) ?? [];
9191
if (items?.length > 0) {
9292
if (allItems.length > 0) {
9393
allItems.push(null);

0 commit comments

Comments
 (0)