markupeditor 0.9.34 → 0.9.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/behaviorconfig.json +2 -1
- package/dist/markup-editor.js +237 -11
- package/package.json +1 -1
package/dist/markup-editor.js
CHANGED
|
@@ -35146,6 +35146,28 @@ function callbackSelectImage() {
|
|
|
35146
35146
|
_callback(JSON.stringify(messageDict));
|
|
35147
35147
|
}
|
|
35148
35148
|
|
|
35149
|
+
/**
|
|
35150
|
+
* Callback to signal that the user wants to insert a link.
|
|
35151
|
+
*
|
|
35152
|
+
* The messageHandler will need to bring up a dialog to identify
|
|
35153
|
+
* the link and then execute insertLink.
|
|
35154
|
+
*/
|
|
35155
|
+
function callbackInsertLink() {
|
|
35156
|
+
let messageDict = { 'messageType' : 'insertLink' };
|
|
35157
|
+
_callback(JSON.stringify(messageDict));
|
|
35158
|
+
}
|
|
35159
|
+
|
|
35160
|
+
/**
|
|
35161
|
+
* Callback to signal that the user wants to insert an image.
|
|
35162
|
+
*
|
|
35163
|
+
* The messageHandler will need to bring up a dialog to identify
|
|
35164
|
+
* the image and then execute insertImage.
|
|
35165
|
+
*/
|
|
35166
|
+
function callbackInsertImage() {
|
|
35167
|
+
let messageDict = { 'messageType' : 'insertImage' };
|
|
35168
|
+
_callback(JSON.stringify(messageDict));
|
|
35169
|
+
}
|
|
35170
|
+
|
|
35149
35171
|
/**
|
|
35150
35172
|
* Callback to signal that user-provided CSS and/or script files have
|
|
35151
35173
|
* been loaded.
|
|
@@ -35454,6 +35476,96 @@ function testPasteTextPreprocessing(html) {
|
|
|
35454
35476
|
function testIsRecognizedLanguage(name) {
|
|
35455
35477
|
return isRecognizedLanguage(name);
|
|
35456
35478
|
}
|
|
35479
|
+
/**
|
|
35480
|
+
* For testing purposes, simulate typing `text` one character at a time
|
|
35481
|
+
* through the `handleTextInput` prop, so input rules (setup/inputrules.js)
|
|
35482
|
+
* fire as they do for live typing. Does not fire the DOM `input` event, so
|
|
35483
|
+
* `callbackInput` (markupeditor.js) is not exercised. Skips `\r`/`\n`
|
|
35484
|
+
* characters rather than inserting them, matching real typing, which never
|
|
35485
|
+
* routes a newline through `handleTextInput`.
|
|
35486
|
+
*
|
|
35487
|
+
* @param {string} text The text to type, one Unicode code point at a time.
|
|
35488
|
+
*/
|
|
35489
|
+
function testTypeText(text) {
|
|
35490
|
+
const view = activeView();
|
|
35491
|
+
for (const ch of text) {
|
|
35492
|
+
if (/[\r\n]/.test(ch)) continue
|
|
35493
|
+
const { from, to } = view.state.selection;
|
|
35494
|
+
const deflt = () => view.state.tr.insertText(ch, from, to);
|
|
35495
|
+
const handled = view.someProp('handleTextInput', f => f(view, from, to, ch, deflt));
|
|
35496
|
+
if (!handled) {
|
|
35497
|
+
view.dispatch(deflt());
|
|
35498
|
+
}
|
|
35499
|
+
}
|
|
35500
|
+
}
|
|
35501
|
+
// Modifier segments testTypeKey recognizes when parsing a keymap-style key
|
|
35502
|
+
// name. "Mod" (prosemirror-keymap's platform-dependent Cmd/Ctrl alias) is
|
|
35503
|
+
// deliberately excluded: it has no single fixed KeyboardEvent flag, and the
|
|
35504
|
+
// one scenario that needed testTypeKey (Backspace, no modifiers) never
|
|
35505
|
+
// required it.
|
|
35506
|
+
const _testTypeKeyModifiers = new Set(['Shift', 'Ctrl', 'Control', 'Alt', 'Cmd', 'Meta']);
|
|
35507
|
+
|
|
35508
|
+
// Reverse lookup from KeyboardEvent.key name to legacy keyCode, built from
|
|
35509
|
+
// w3c-keyname's public `base` table (keyCode -> name). Where more than one
|
|
35510
|
+
// keyCode maps to the same name (e.g. 10 and 13 both name "Enter"), the
|
|
35511
|
+
// higher/later entry wins, matching prosemirror-view's hardcoded
|
|
35512
|
+
// convention (its internal key-event helper in src/dom.ts pairs "Enter"
|
|
35513
|
+
// with 13 and "Backspace" with 8 at its call sites).
|
|
35514
|
+
const _testKeyCodeByName = Object.fromEntries(
|
|
35515
|
+
Object.entries(base).map(([code, name]) => [name, Number(code)])
|
|
35516
|
+
);
|
|
35517
|
+
|
|
35518
|
+
function _testKeyCodeFor(key) {
|
|
35519
|
+
return _testKeyCodeByName[key] ?? 0
|
|
35520
|
+
}
|
|
35521
|
+
|
|
35522
|
+
/**
|
|
35523
|
+
* For testing purposes, simulate a single keydown through the `handleKeyDown`
|
|
35524
|
+
* prop, so keymap bindings (setup/keymap.js) fire as they do for a live
|
|
35525
|
+
* keypress. Exercises only handleKeyDown-routed (keymap-bound) behavior: for
|
|
35526
|
+
* anything the browser would otherwise handle natively instead of a
|
|
35527
|
+
* registered binding claiming it (e.g. Backspace when there's no input-rule
|
|
35528
|
+
* state to undo, IME composition), this is a silent no-op — it returns
|
|
35529
|
+
* `false` and does nothing, unlike a real keypress.
|
|
35530
|
+
*
|
|
35531
|
+
* @param {string} key A keymap-style key name (e.g., "Backspace",
|
|
35532
|
+
* "Shift-Enter"): zero or more modifier prefixes
|
|
35533
|
+
* (Shift-, Ctrl-/Control-, Alt-, Cmd-/Meta-)
|
|
35534
|
+
* followed by a KeyboardEvent.key value.
|
|
35535
|
+
* @throws {Error} If `key` contains an unrecognized modifier
|
|
35536
|
+
* prefix, including the unsupported "Mod-".
|
|
35537
|
+
* @returns {boolean} Whether a handler returned `true` for the key.
|
|
35538
|
+
* NOT a reliable "the document changed" signal:
|
|
35539
|
+
* some commands (e.g. setStyleCommand,
|
|
35540
|
+
* toggleFormatCommand) dispatch without returning
|
|
35541
|
+
* `true`, so the document can still mutate while
|
|
35542
|
+
* this returns `false`.
|
|
35543
|
+
*/
|
|
35544
|
+
function testTypeKey(key) {
|
|
35545
|
+
const view = activeView();
|
|
35546
|
+
// Split like prosemirror-keymap's normalizeKeyName does, so a
|
|
35547
|
+
// trailing "-" (or a bare "-") is recognized as the literal key rather
|
|
35548
|
+
// than an empty string, e.g. "Ctrl--" -> ["Ctrl", "-"].
|
|
35549
|
+
const parts = key.split(/-(?!$)/);
|
|
35550
|
+
const eventKey = parts.pop();
|
|
35551
|
+
const modifiers = new Set(parts);
|
|
35552
|
+
for (const modifier of modifiers) {
|
|
35553
|
+
if (!_testTypeKeyModifiers.has(modifier)) {
|
|
35554
|
+
throw new Error(`testTypeKey: unrecognized modifier "${modifier}" in "${key}"`)
|
|
35555
|
+
}
|
|
35556
|
+
}
|
|
35557
|
+
const event = new KeyboardEvent('keydown', {
|
|
35558
|
+
key: eventKey,
|
|
35559
|
+
keyCode: _testKeyCodeFor(eventKey),
|
|
35560
|
+
shiftKey: modifiers.has('Shift'),
|
|
35561
|
+
ctrlKey: modifiers.has('Ctrl') || modifiers.has('Control'),
|
|
35562
|
+
altKey: modifiers.has('Alt'),
|
|
35563
|
+
metaKey: modifiers.has('Cmd') || modifiers.has('Meta'),
|
|
35564
|
+
bubbles: true,
|
|
35565
|
+
cancelable: true,
|
|
35566
|
+
});
|
|
35567
|
+
return view.someProp('handleKeyDown', f => f(view, event)) ?? false
|
|
35568
|
+
}
|
|
35457
35569
|
/**
|
|
35458
35570
|
* For testing purposes, invoke presentCodeLanguages on the active document.
|
|
35459
35571
|
*/
|
|
@@ -36987,12 +37099,14 @@ var selectImage = false;
|
|
|
36987
37099
|
var insertLink = false;
|
|
36988
37100
|
var insertImage = false;
|
|
36989
37101
|
var highlightCode = true;
|
|
37102
|
+
var markdownShorthand = true;
|
|
36990
37103
|
var behaviorConfig = {
|
|
36991
37104
|
focusAfterLoad: focusAfterLoad,
|
|
36992
37105
|
selectImage: selectImage,
|
|
36993
37106
|
insertLink: insertLink,
|
|
36994
37107
|
insertImage: insertImage,
|
|
36995
|
-
highlightCode: highlightCode
|
|
37108
|
+
highlightCode: highlightCode,
|
|
37109
|
+
markdownShorthand: markdownShorthand
|
|
36996
37110
|
};
|
|
36997
37111
|
|
|
36998
37112
|
/**
|
|
@@ -37031,7 +37145,9 @@ var behaviorConfig = {
|
|
|
37031
37145
|
* "selectImage": false, // Whether to show a "Select..." button in the Insert Image dialog
|
|
37032
37146
|
* "insertLink": false, // Whether to defer to the MarkupDelegate rather than use the default LinkDialog
|
|
37033
37147
|
* "insertImage": false, // Whether to defer to the MarkupDelagate rather than use the default ImageDialog
|
|
37034
|
-
* "highlightCode": true
|
|
37148
|
+
* "highlightCode": true, // Whether to highlight code blocks and support language identificaton in UI
|
|
37149
|
+
* "markdownShorthand": true // Whether typing markdown shorthand converts to formatting: block-level
|
|
37150
|
+
* // (`> `, list markers, ``` ``` ```, `#`) and inline (**, *, _, `, ~~)
|
|
37035
37151
|
* }
|
|
37036
37152
|
* ```
|
|
37037
37153
|
*/
|
|
@@ -40864,16 +40980,122 @@ function headingRule(nodeType, maxLevel) {
|
|
|
40864
40980
|
nodeType, match => ({level: match[1].length}))
|
|
40865
40981
|
}
|
|
40866
40982
|
|
|
40867
|
-
// : (
|
|
40983
|
+
// : (RegExp, MarkType, number, number) → InputRule
|
|
40984
|
+
// Given a regexp matching a markdown emphasis pattern ending at the
|
|
40985
|
+
// cursor, a mark type, and the lengths of the opening and closing
|
|
40986
|
+
// delimiters, returns an input rule that deletes only the
|
|
40987
|
+
// delimiters -- never the content between them -- and applies the
|
|
40988
|
+
// mark over the untouched range. This preserves any marks (links,
|
|
40989
|
+
// nested emphasis, etc.) already present in the converted range
|
|
40990
|
+
// instead of flattening it to plain text.
|
|
40991
|
+
//
|
|
40992
|
+
// prosemirror-inputrules invokes this handler from handleTextInput,
|
|
40993
|
+
// before the browser's pending keystroke has actually been applied
|
|
40994
|
+
// to the document -- match[0] (built from existing text plus the
|
|
40995
|
+
// not-yet-inserted text) can therefore be longer than end - start.
|
|
40996
|
+
// That trailing slice is inserted first so the full matched range
|
|
40997
|
+
// genuinely exists in the document before the delimiter surgery
|
|
40998
|
+
// below operates on it. Suppressed when the cursor already sits
|
|
40999
|
+
// inside a code mark, since markdown shorthand characters are meant
|
|
41000
|
+
// to stay literal there. Clears the mark from stored marks afterward
|
|
41001
|
+
// so text typed immediately after the conversion does not inherit
|
|
41002
|
+
// it.
|
|
41003
|
+
//
|
|
41004
|
+
// The leading delimiter is deleted before the trailing one, so the
|
|
41005
|
+
// transaction's last content-shifting step is the trailing-delimiter
|
|
41006
|
+
// delete, ending at the cursor -- prosemirror-history's grouping
|
|
41007
|
+
// heuristic only looks at that step's range when deciding whether
|
|
41008
|
+
// the next keystroke belongs to the same undo group (addMark's own
|
|
41009
|
+
// step contributes no range there), so ending at the cursor is what
|
|
41010
|
+
// keeps immediately-following typing (e.g. "**foo**bar") merged with
|
|
41011
|
+
// the conversion into a single undo.
|
|
41012
|
+
function markInputRule(regexp, markType, openLen, closeLen) {
|
|
41013
|
+
return new InputRule(regexp, (state, match, start, end) => {
|
|
41014
|
+
const codeType = state.schema.marks.code;
|
|
41015
|
+
if (codeType && state.doc.resolve(start).marks().some(mark => mark.type === codeType)) return null
|
|
41016
|
+
const tr = state.tr;
|
|
41017
|
+
const fullEnd = start + match[0].length;
|
|
41018
|
+
if (fullEnd > end) tr.insertText(match[0].slice(end - start), end);
|
|
41019
|
+
tr.delete(start, start + openLen);
|
|
41020
|
+
const closeStart = fullEnd - openLen - closeLen;
|
|
41021
|
+
tr.delete(closeStart, closeStart + closeLen);
|
|
41022
|
+
tr.addMark(start, closeStart, markType.create());
|
|
41023
|
+
tr.removeStoredMark(markType);
|
|
41024
|
+
return tr
|
|
41025
|
+
})
|
|
41026
|
+
}
|
|
41027
|
+
|
|
41028
|
+
// : (MarkType) → InputRule
|
|
41029
|
+
// Given the strong mark type, returns an input rule that converts
|
|
41030
|
+
// `**text**` at the cursor into bold.
|
|
41031
|
+
function strongRule(markType) {
|
|
41032
|
+
return markInputRule(/\*\*([^*\s](?:[^*]*[^*\s])?)\*\*$/, markType, 2, 2)
|
|
41033
|
+
}
|
|
41034
|
+
|
|
41035
|
+
// : (MarkType) → InputRule
|
|
41036
|
+
// Given the em mark type, returns an input rule that converts
|
|
41037
|
+
// `*text*` at the cursor into italic. The negative lookbehind on the
|
|
41038
|
+
// opening `*` defers matching until a preceding, still-unconsumed
|
|
41039
|
+
// `*` is no longer in the way, so this rule does not fire on a
|
|
41040
|
+
// partially typed `**text**` before bold's closing marker
|
|
41041
|
+
// completes.
|
|
41042
|
+
function emStarRule(markType) {
|
|
41043
|
+
return markInputRule(/(?<!\*)\*([^*\s](?:[^*]*[^*\s])?)\*$/, markType, 1, 1)
|
|
41044
|
+
}
|
|
41045
|
+
|
|
41046
|
+
// : (MarkType) → InputRule
|
|
41047
|
+
// Given the em mark type, returns an input rule that converts
|
|
41048
|
+
// `_text_` at the cursor into italic. The negative lookbehind on the
|
|
41049
|
+
// opening `_` blocks intraword underscores (`\w` includes `_`), per
|
|
41050
|
+
// CommonMark's flanking rule for `_` emphasis -- unlike `*`, `_`
|
|
41051
|
+
// emphasis must not fire inside a word, so identifiers like
|
|
41052
|
+
// `snake_case_name` stay literal.
|
|
41053
|
+
function emUnderscoreRule(markType) {
|
|
41054
|
+
return markInputRule(/(?<!\w)_([^_\s](?:[^_]*[^_\s])?)_$/, markType, 1, 1)
|
|
41055
|
+
}
|
|
41056
|
+
|
|
41057
|
+
// : (MarkType) → InputRule
|
|
41058
|
+
// Given the code mark type, returns an input rule that converts a
|
|
41059
|
+
// backtick-delimited `text` at the cursor into inline code.
|
|
41060
|
+
function codeRule(markType) {
|
|
41061
|
+
return markInputRule(/(?<!`)`([^`\s](?:[^`]*[^`\s])?)`$/, markType, 1, 1)
|
|
41062
|
+
}
|
|
41063
|
+
|
|
41064
|
+
// : (MarkType) → InputRule
|
|
41065
|
+
// Given the s (strikethrough) mark type, returns an input rule that
|
|
41066
|
+
// converts `~~text~~` at the cursor into strikethrough. No
|
|
41067
|
+
// self-referential lookbehind, matching strongRule -- both are
|
|
41068
|
+
// double-delimiter patterns with no single-character sibling rule to
|
|
41069
|
+
// defer against, unlike emStarRule's genuine need to defer to bold.
|
|
41070
|
+
function strikethroughRule(markType) {
|
|
41071
|
+
return markInputRule(/~~([^~\s](?:[^~]*[^~\s])?)~~$/, markType, 2, 2)
|
|
41072
|
+
}
|
|
41073
|
+
|
|
41074
|
+
// : (Schema, object) → Plugin
|
|
40868
41075
|
// A set of input rules for creating the basic block quotes, lists,
|
|
40869
|
-
// code blocks, and
|
|
40870
|
-
|
|
41076
|
+
// code blocks, heading, and markdown formatting shorthand (bold,
|
|
41077
|
+
// italic, inline code, strikethrough). All ten rules are gated
|
|
41078
|
+
// together by config.behavior.markdownShorthand. config defaults to
|
|
41079
|
+
// {}, so markdownShorthand defaults to enabled (only an explicit
|
|
41080
|
+
// `false` turns it off) when buildInputRules is called without a
|
|
41081
|
+
// config, matching BehaviorConfig's default.
|
|
41082
|
+
function buildInputRules(schema, config = {}) {
|
|
40871
41083
|
let rules = [], type;
|
|
40872
|
-
|
|
40873
|
-
if (
|
|
40874
|
-
|
|
40875
|
-
|
|
40876
|
-
|
|
41084
|
+
const markdownShorthand = config.behavior?.markdownShorthand !== false;
|
|
41085
|
+
if (markdownShorthand) {
|
|
41086
|
+
if (type = schema.nodes.blockquote) rules.push(blockQuoteRule(type));
|
|
41087
|
+
if (type = schema.nodes.ordered_list) rules.push(orderedListRule(type));
|
|
41088
|
+
if (type = schema.nodes.bullet_list) rules.push(bulletListRule(type));
|
|
41089
|
+
if (type = schema.nodes.code_block) rules.push(codeBlockRule(type));
|
|
41090
|
+
if (type = schema.nodes.heading) rules.push(headingRule(type, 6));
|
|
41091
|
+
if (type = schema.marks.strong) rules.push(strongRule(type));
|
|
41092
|
+
if (type = schema.marks.em) {
|
|
41093
|
+
rules.push(emStarRule(type));
|
|
41094
|
+
rules.push(emUnderscoreRule(type));
|
|
41095
|
+
}
|
|
41096
|
+
if (type = schema.marks.code) rules.push(codeRule(type));
|
|
41097
|
+
if (type = schema.marks.s) rules.push(strikethroughRule(type));
|
|
41098
|
+
}
|
|
40877
41099
|
return inputRules({rules})
|
|
40878
41100
|
}
|
|
40879
41101
|
|
|
@@ -41154,7 +41376,7 @@ function openImageDialog() {
|
|
|
41154
41376
|
function markupSetup(config, schema) {
|
|
41155
41377
|
setPrefix('Markup');
|
|
41156
41378
|
let plugins = [
|
|
41157
|
-
buildInputRules(schema),
|
|
41379
|
+
buildInputRules(schema, config),
|
|
41158
41380
|
keymap(buildKeymap(config, schema)),
|
|
41159
41381
|
keymap(baseKeymap),
|
|
41160
41382
|
dropCursor(),
|
|
@@ -42506,6 +42728,8 @@ const MU = {
|
|
|
42506
42728
|
addHeader,
|
|
42507
42729
|
addRow,
|
|
42508
42730
|
borderTable,
|
|
42731
|
+
callbackInsertImage,
|
|
42732
|
+
callbackInsertLink,
|
|
42509
42733
|
callbackSelectImage,
|
|
42510
42734
|
cancelSearch,
|
|
42511
42735
|
canUndo,
|
|
@@ -42566,6 +42790,8 @@ const MU = {
|
|
|
42566
42790
|
testPasteHTMLPreprocessing,
|
|
42567
42791
|
testPasteTextPreprocessing,
|
|
42568
42792
|
testPresentCodeLanguages,
|
|
42793
|
+
testTypeKey,
|
|
42794
|
+
testTypeText,
|
|
42569
42795
|
toggleBold,
|
|
42570
42796
|
toggleCode,
|
|
42571
42797
|
toggleItalic,
|