mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2025-04-22 10:43:11 +00:00
lint: indent with tab
This commit is contained in:
parent
348427733b
commit
d32048fc6e
plugins/tiddlywiki/prosemirror
@ -8,95 +8,95 @@ Get the Wiki AST from a Prosemirror AST
|
||||
\*/
|
||||
|
||||
function doc(context, node) {
|
||||
return convertNodes(context, node.content);
|
||||
return convertNodes(context, node.content);
|
||||
}
|
||||
|
||||
function paragraph(context, node) {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "p",
|
||||
rule: "parseblock",
|
||||
children: convertNodes(context, node.content)
|
||||
};
|
||||
return {
|
||||
type: "element",
|
||||
tag: "p",
|
||||
rule: "parseblock",
|
||||
children: convertNodes(context, node.content)
|
||||
};
|
||||
}
|
||||
|
||||
function text(context, node) {
|
||||
return {
|
||||
type: "text",
|
||||
text: node.text
|
||||
}
|
||||
return {
|
||||
type: "text",
|
||||
text: node.text
|
||||
}
|
||||
}
|
||||
|
||||
function heading(context, node) {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "h" + node.attrs.level,
|
||||
rule: "heading",
|
||||
attributes: {
|
||||
// TODO: restore class if any
|
||||
},
|
||||
children: convertNodes(context, node.content)
|
||||
};
|
||||
return {
|
||||
type: "element",
|
||||
tag: "h" + node.attrs.level,
|
||||
rule: "heading",
|
||||
attributes: {
|
||||
// TODO: restore class if any
|
||||
},
|
||||
children: convertNodes(context, node.content)
|
||||
};
|
||||
}
|
||||
|
||||
function list(context, node) {
|
||||
const listType = node.attrs && node.attrs.kind === "ordered" ? "ol" : "ul";
|
||||
|
||||
const listItems = node.content.map(item => {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "li",
|
||||
children: convertANode(context, item)
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
type: "element",
|
||||
tag: listType,
|
||||
rule: "list",
|
||||
children: listItems
|
||||
};
|
||||
const listType = node.attrs && node.attrs.kind === "ordered" ? "ol" : "ul";
|
||||
|
||||
const listItems = node.content.map(item => {
|
||||
return {
|
||||
type: "element",
|
||||
tag: "li",
|
||||
children: convertANode(context, item)
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
type: "element",
|
||||
tag: listType,
|
||||
rule: "list",
|
||||
children: listItems
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Key is `node.type`, value is node converter function.
|
||||
*/
|
||||
const builders = {
|
||||
doc,
|
||||
paragraph,
|
||||
text,
|
||||
heading,
|
||||
list,
|
||||
doc,
|
||||
paragraph,
|
||||
text,
|
||||
heading,
|
||||
list,
|
||||
};
|
||||
|
||||
function wikiAstFromProseMirrorAst(input) {
|
||||
return convertNodes(builders, Array.isArray(input) ? input : [input]);
|
||||
return convertNodes(builders, Array.isArray(input) ? input : [input]);
|
||||
}
|
||||
|
||||
exports.from = wikiAstFromProseMirrorAst;
|
||||
|
||||
function convertNodes(builders, nodes) {
|
||||
if (nodes === undefined || nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (nodes === undefined || nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return nodes.reduce((accumulator, node) => {
|
||||
return [...accumulator, ...convertANode(builders, node)];
|
||||
}, []);
|
||||
return nodes.reduce((accumulator, node) => {
|
||||
return [...accumulator, ...convertANode(builders, node)];
|
||||
}, []);
|
||||
}
|
||||
|
||||
function restoreMetadata(node) {
|
||||
// TODO: restore attributes, orderedAttributes, isBlock
|
||||
return {};
|
||||
// TODO: restore attributes, orderedAttributes, isBlock
|
||||
return {};
|
||||
}
|
||||
function convertANode(builders, node) {
|
||||
var builder = builders[node.type];
|
||||
if (typeof builder === 'function') {
|
||||
var convertedNode = builder(builders, node);
|
||||
var arrayOfNodes = (Array.isArray(convertedNode)
|
||||
? convertedNode : [convertedNode]);
|
||||
return arrayOfNodes.map((child) => ({ ...restoreMetadata(node), ...child }));
|
||||
}
|
||||
console.warn(`WikiAst get Unknown node type: ${JSON.stringify(node)}`);
|
||||
return [];
|
||||
var builder = builders[node.type];
|
||||
if (typeof builder === 'function') {
|
||||
var convertedNode = builder(builders, node);
|
||||
var arrayOfNodes = (Array.isArray(convertedNode)
|
||||
? convertedNode : [convertedNode]);
|
||||
return arrayOfNodes.map((child) => ({ ...restoreMetadata(node), ...child }));
|
||||
}
|
||||
console.warn(`WikiAst get Unknown node type: ${JSON.stringify(node)}`);
|
||||
return [];
|
||||
}
|
||||
|
@ -11,85 +11,85 @@ Get the Prosemirror AST from a Wiki AST
|
||||
* Many node shares same type `element` in wikiAst, we need to distinguish them by tag.
|
||||
*/
|
||||
const elementBuilders = {
|
||||
p: function(context, node) {
|
||||
return {
|
||||
type: "paragraph",
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h1: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 1 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h2: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 2 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h3: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 3 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h4: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 4 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h5: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 5 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h6: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 6 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
ul: function(context, node) {
|
||||
return {
|
||||
type: "list",
|
||||
attrs: {
|
||||
kind: "bullet",
|
||||
order: null,
|
||||
checked: false,
|
||||
collapsed: false
|
||||
},
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
ol: function(context, node) {
|
||||
return {
|
||||
type: "list",
|
||||
attrs: {
|
||||
kind: "ordered",
|
||||
order: null,
|
||||
checked: false,
|
||||
collapsed: false
|
||||
},
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
li: function(context, node) {
|
||||
// In ProseMirror, list items are converted to paragraphs or other block content
|
||||
// directly under the list node, no special list_item type needed
|
||||
const processedContent = convertNodes(context, node.children);
|
||||
// Ensure content starts with a block element (typically paragraph)
|
||||
return wrapTextNodesInParagraphs(context, processedContent);
|
||||
}
|
||||
p: function(context, node) {
|
||||
return {
|
||||
type: "paragraph",
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h1: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 1 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h2: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 2 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h3: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 3 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h4: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 4 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h5: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 5 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
h6: function(context, node) {
|
||||
return {
|
||||
type: "heading",
|
||||
attrs: { level: 6 },
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
ul: function(context, node) {
|
||||
return {
|
||||
type: "list",
|
||||
attrs: {
|
||||
kind: "bullet",
|
||||
order: null,
|
||||
checked: false,
|
||||
collapsed: false
|
||||
},
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
ol: function(context, node) {
|
||||
return {
|
||||
type: "list",
|
||||
attrs: {
|
||||
kind: "ordered",
|
||||
order: null,
|
||||
checked: false,
|
||||
collapsed: false
|
||||
},
|
||||
content: convertNodes(context, node.children)
|
||||
};
|
||||
},
|
||||
li: function(context, node) {
|
||||
// In ProseMirror, list items are converted to paragraphs or other block content
|
||||
// directly under the list node, no special list_item type needed
|
||||
const processedContent = convertNodes(context, node.children);
|
||||
// Ensure content starts with a block element (typically paragraph)
|
||||
return wrapTextNodesInParagraphs(context, processedContent);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -97,101 +97,101 @@ const elementBuilders = {
|
||||
* ProseMirror requires list items to contain block content, not bare text
|
||||
*/
|
||||
function wrapTextNodesInParagraphs(context, nodes) {
|
||||
if (!nodes || nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (!nodes || nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const result = [];
|
||||
let currentTextNodes = [];
|
||||
const result = [];
|
||||
let currentTextNodes = [];
|
||||
|
||||
function flushTextNodes() {
|
||||
if (currentTextNodes.length > 0) {
|
||||
result.push({
|
||||
type: "paragraph",
|
||||
content: currentTextNodes
|
||||
});
|
||||
currentTextNodes = [];
|
||||
}
|
||||
}
|
||||
function flushTextNodes() {
|
||||
if (currentTextNodes.length > 0) {
|
||||
result.push({
|
||||
type: "paragraph",
|
||||
content: currentTextNodes
|
||||
});
|
||||
currentTextNodes = [];
|
||||
}
|
||||
}
|
||||
|
||||
nodes.forEach(node => {
|
||||
// If it's a text node, collect it
|
||||
if (node.type === "text") {
|
||||
currentTextNodes.push(node);
|
||||
} else {
|
||||
// If we encounter a non-text node, flush any collected text nodes
|
||||
flushTextNodes();
|
||||
// Add the non-text node as is
|
||||
result.push(node);
|
||||
}
|
||||
});
|
||||
nodes.forEach(node => {
|
||||
// If it's a text node, collect it
|
||||
if (node.type === "text") {
|
||||
currentTextNodes.push(node);
|
||||
} else {
|
||||
// If we encounter a non-text node, flush any collected text nodes
|
||||
flushTextNodes();
|
||||
// Add the non-text node as is
|
||||
result.push(node);
|
||||
}
|
||||
});
|
||||
|
||||
// Flush any remaining text nodes
|
||||
flushTextNodes();
|
||||
// Flush any remaining text nodes
|
||||
flushTextNodes();
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
function element(context, node) {
|
||||
const builder = elementBuilders[node.tag];
|
||||
if (builder) {
|
||||
return builder(context, node);
|
||||
} else {
|
||||
console.warn(`Unknown element tag: ${node.tag}`);
|
||||
return [];
|
||||
}
|
||||
const builder = elementBuilders[node.tag];
|
||||
if (builder) {
|
||||
return builder(context, node);
|
||||
} else {
|
||||
console.warn(`Unknown element tag: ${node.tag}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function text(context, node) {
|
||||
return {
|
||||
type: "text",
|
||||
text: node.text
|
||||
};
|
||||
return {
|
||||
type: "text",
|
||||
text: node.text
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Key is wikiAst node type, value is node converter function.
|
||||
*/
|
||||
const builders = {
|
||||
element,
|
||||
text
|
||||
element,
|
||||
text
|
||||
};
|
||||
|
||||
function wikiAstToProsemirrorAst(node, options) {
|
||||
const context = { ...builders, ...options };
|
||||
const result = convertNodes(context, Array.isArray(node) ? node : [node]);
|
||||
|
||||
// Wrap in a doc if needed
|
||||
if (result.length > 0 && result[0].type !== "doc") {
|
||||
return {
|
||||
type: "doc",
|
||||
content: result
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
const context = { ...builders, ...options };
|
||||
const result = convertNodes(context, Array.isArray(node) ? node : [node]);
|
||||
|
||||
// Wrap in a doc if needed
|
||||
if (result.length > 0 && result[0].type !== "doc") {
|
||||
return {
|
||||
type: "doc",
|
||||
content: result
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
exports.to = wikiAstToProsemirrorAst;
|
||||
|
||||
function convertNodes(context, nodes) {
|
||||
if (nodes === undefined || nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (nodes === undefined || nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return nodes.reduce((accumulator, node) => {
|
||||
return [...accumulator, ...convertANode(context, node)];
|
||||
}, []);
|
||||
return nodes.reduce((accumulator, node) => {
|
||||
return [...accumulator, ...convertANode(context, node)];
|
||||
}, []);
|
||||
}
|
||||
|
||||
function convertANode(context, node) {
|
||||
var builder = context[node.type];
|
||||
if (typeof builder === 'function') {
|
||||
var convertedNode = builder(context, node);
|
||||
var arrayOfNodes = (Array.isArray(convertedNode)
|
||||
? convertedNode : [convertedNode]);
|
||||
return arrayOfNodes;
|
||||
}
|
||||
console.warn(`ProseMirror get Unknown node type: ${JSON.stringify(node)}`);
|
||||
return [];
|
||||
var builder = context[node.type];
|
||||
if (typeof builder === 'function') {
|
||||
var convertedNode = builder(context, node);
|
||||
var arrayOfNodes = (Array.isArray(convertedNode)
|
||||
? convertedNode : [convertedNode]);
|
||||
return arrayOfNodes;
|
||||
}
|
||||
console.warn(`ProseMirror get Unknown node type: ${JSON.stringify(node)}`);
|
||||
return [];
|
||||
}
|
||||
|
@ -11,34 +11,38 @@ var { inputRules, wrappingInputRule, textblockTypeInputRule, smartQuotes, emDash
|
||||
var { NodeType, Schema } = require("prosemirror-model");
|
||||
|
||||
function blockQuoteRule(nodeType) {
|
||||
return wrappingInputRule(/^\s*>\s$/, nodeType);
|
||||
return wrappingInputRule(/^\s*>\s$/, nodeType);
|
||||
}
|
||||
|
||||
function orderedListRule(nodeType) {
|
||||
return wrappingInputRule(/^(\d+)\.\s$/, nodeType, function(match) { return { order: +match[1] }; },
|
||||
function(match, node) { return node.childCount + node.attrs.order == +match[1]; });
|
||||
return wrappingInputRule(
|
||||
/^(\d+)\.\s$/,
|
||||
nodeType,
|
||||
function(match) { return { order: +match[1] }; },
|
||||
function(match, node) { return node.childCount + node.attrs.order == +match[1]; }
|
||||
);
|
||||
}
|
||||
|
||||
function bulletListRule(nodeType) {
|
||||
return wrappingInputRule(/^\s*([-+*])\s$/, nodeType);
|
||||
return wrappingInputRule(/^\s*([-+*])\s$/, nodeType);
|
||||
}
|
||||
|
||||
function codeBlockRule(nodeType) {
|
||||
return textblockTypeInputRule(/^```$/, nodeType);
|
||||
return textblockTypeInputRule(/^```$/, nodeType);
|
||||
}
|
||||
|
||||
function headingRule(nodeType, maxLevel) {
|
||||
return textblockTypeInputRule(new RegExp("^(#{1," + maxLevel + "})\\s$"), nodeType, function(match) { return { level: match[1].length }; });
|
||||
return textblockTypeInputRule(new RegExp("^(#{1," + maxLevel + "})\\s$"), nodeType, function(match) { return { level: match[1].length }; });
|
||||
}
|
||||
|
||||
function buildInputRules(schema) {
|
||||
var rules = smartQuotes.concat(ellipsis, emDash), type;
|
||||
if (type = schema.nodes.blockquote) rules.push(blockQuoteRule(type));
|
||||
if (type = schema.nodes.ordered_list) rules.push(orderedListRule(type));
|
||||
if (type = schema.nodes.bullet_list) rules.push(bulletListRule(type));
|
||||
if (type = schema.nodes.code_block) rules.push(codeBlockRule(type));
|
||||
if (type = schema.nodes.heading) rules.push(headingRule(type, 6));
|
||||
return inputRules({ rules: rules });
|
||||
var rules = smartQuotes.concat(ellipsis, emDash), type;
|
||||
if (type = schema.nodes.blockquote) rules.push(blockQuoteRule(type));
|
||||
if (type = schema.nodes.ordered_list) rules.push(orderedListRule(type));
|
||||
if (type = schema.nodes.bullet_list) rules.push(bulletListRule(type));
|
||||
if (type = schema.nodes.code_block) rules.push(codeBlockRule(type));
|
||||
if (type = schema.nodes.heading) rules.push(headingRule(type, 6));
|
||||
return inputRules({ rules: rules });
|
||||
}
|
||||
|
||||
exports.buildInputRules = buildInputRules;
|
||||
|
@ -17,68 +17,68 @@ var prosemirrorModel = require("prosemirror-model");
|
||||
var mac = typeof navigator != "undefined" ? /Mac|iP(hone|[oa]d)/.test(navigator.platform) : false;
|
||||
|
||||
function buildKeymap(schema, mapKeys) {
|
||||
var keys = {}, type;
|
||||
function bind(key, cmd) {
|
||||
if (mapKeys) {
|
||||
var mapped = mapKeys[key];
|
||||
if (mapped === false) return;
|
||||
if (mapped) key = mapped;
|
||||
}
|
||||
keys[key] = cmd;
|
||||
}
|
||||
var keys = {}, type;
|
||||
function bind(key, cmd) {
|
||||
if (mapKeys) {
|
||||
var mapped = mapKeys[key];
|
||||
if (mapped === false) return;
|
||||
if (mapped) key = mapped;
|
||||
}
|
||||
keys[key] = cmd;
|
||||
}
|
||||
|
||||
bind("Mod-z", prosemirrorHistory.undo);
|
||||
bind("Shift-Mod-z", prosemirrorHistory.redo);
|
||||
bind("Backspace", prosemirrorInputrules.undoInputRule);
|
||||
if (!mac) bind("Mod-y", prosemirrorHistory.redo);
|
||||
bind("Mod-z", prosemirrorHistory.undo);
|
||||
bind("Shift-Mod-z", prosemirrorHistory.redo);
|
||||
bind("Backspace", prosemirrorInputrules.undoInputRule);
|
||||
if (!mac) bind("Mod-y", prosemirrorHistory.redo);
|
||||
|
||||
bind("Alt-ArrowUp", prosemirrorCommands.joinUp);
|
||||
bind("Alt-ArrowDown", prosemirrorCommands.joinDown);
|
||||
bind("Mod-BracketLeft", prosemirrorCommands.lift);
|
||||
bind("Escape", prosemirrorCommands.selectParentNode);
|
||||
bind("Alt-ArrowUp", prosemirrorCommands.joinUp);
|
||||
bind("Alt-ArrowDown", prosemirrorCommands.joinDown);
|
||||
bind("Mod-BracketLeft", prosemirrorCommands.lift);
|
||||
bind("Escape", prosemirrorCommands.selectParentNode);
|
||||
|
||||
if (type = schema.marks.strong) {
|
||||
bind("Mod-b", prosemirrorCommands.toggleMark(type));
|
||||
bind("Mod-B", prosemirrorCommands.toggleMark(type));
|
||||
}
|
||||
if (type = schema.marks.em) {
|
||||
bind("Mod-i", prosemirrorCommands.toggleMark(type));
|
||||
bind("Mod-I", prosemirrorCommands.toggleMark(type));
|
||||
}
|
||||
if (type = schema.marks.code)
|
||||
bind("Mod-`", prosemirrorCommands.toggleMark(type));
|
||||
if (type = schema.nodes.blockquote)
|
||||
bind("Ctrl->", prosemirrorCommands.wrapIn(type));
|
||||
if (type = schema.nodes.hard_break) {
|
||||
var br = type, cmd = prosemirrorCommands.chainCommands(prosemirrorCommands.exitCode, function(state, dispatch) {
|
||||
if (dispatch) dispatch(state.tr.replaceSelectionWith(br.create()).scrollIntoView());
|
||||
return true;
|
||||
});
|
||||
bind("Mod-Enter", cmd);
|
||||
bind("Shift-Enter", cmd);
|
||||
if (mac) bind("Ctrl-Enter", cmd);
|
||||
}
|
||||
if (type = schema.nodes.list) {
|
||||
bind("Shift-Tab", prosemirrorFlatList.createDedentListCommand(type));
|
||||
bind("Tab", prosemirrorFlatList.createIndentListCommand(type));
|
||||
}
|
||||
if (type = schema.nodes.paragraph)
|
||||
bind("Shift-Ctrl-0", prosemirrorCommands.setBlockType(type));
|
||||
if (type = schema.nodes.code_block)
|
||||
bind("Shift-Ctrl-\\", prosemirrorCommands.setBlockType(type));
|
||||
if (type = schema.nodes.heading)
|
||||
for (var i = 1; i <= 6; i++) bind("Shift-Ctrl-" + i, prosemirrorCommands.setBlockType(type, {level: i}));
|
||||
if (type = schema.nodes.horizontal_rule) {
|
||||
var hr = type;
|
||||
bind("Mod-_", function(state, dispatch) {
|
||||
if (dispatch) dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (type = schema.marks.strong) {
|
||||
bind("Mod-b", prosemirrorCommands.toggleMark(type));
|
||||
bind("Mod-B", prosemirrorCommands.toggleMark(type));
|
||||
}
|
||||
if (type = schema.marks.em) {
|
||||
bind("Mod-i", prosemirrorCommands.toggleMark(type));
|
||||
bind("Mod-I", prosemirrorCommands.toggleMark(type));
|
||||
}
|
||||
if (type = schema.marks.code)
|
||||
bind("Mod-`", prosemirrorCommands.toggleMark(type));
|
||||
if (type = schema.nodes.blockquote)
|
||||
bind("Ctrl->", prosemirrorCommands.wrapIn(type));
|
||||
if (type = schema.nodes.hard_break) {
|
||||
var br = type, cmd = prosemirrorCommands.chainCommands(prosemirrorCommands.exitCode, function(state, dispatch) {
|
||||
if (dispatch) dispatch(state.tr.replaceSelectionWith(br.create()).scrollIntoView());
|
||||
return true;
|
||||
});
|
||||
bind("Mod-Enter", cmd);
|
||||
bind("Shift-Enter", cmd);
|
||||
if (mac) bind("Ctrl-Enter", cmd);
|
||||
}
|
||||
if (type = schema.nodes.list) {
|
||||
bind("Shift-Tab", prosemirrorFlatList.createDedentListCommand(type));
|
||||
bind("Tab", prosemirrorFlatList.createIndentListCommand(type));
|
||||
}
|
||||
if (type = schema.nodes.paragraph)
|
||||
bind("Shift-Ctrl-0", prosemirrorCommands.setBlockType(type));
|
||||
if (type = schema.nodes.code_block)
|
||||
bind("Shift-Ctrl-\\", prosemirrorCommands.setBlockType(type));
|
||||
if (type = schema.nodes.heading)
|
||||
for (var i = 1; i <= 6; i++) bind("Shift-Ctrl-" + i, prosemirrorCommands.setBlockType(type, {level: i}));
|
||||
if (type = schema.nodes.horizontal_rule) {
|
||||
var hr = type;
|
||||
bind("Mod-_", function(state, dispatch) {
|
||||
if (dispatch) dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return keys;
|
||||
return keys;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildKeymap: buildKeymap
|
||||
buildKeymap: buildKeymap
|
||||
};
|
||||
|
@ -8,18 +8,18 @@ module-type: library
|
||||
"use strict";
|
||||
|
||||
var {
|
||||
wrapItem,
|
||||
blockTypeItem,
|
||||
Dropdown,
|
||||
DropdownSubmenu,
|
||||
joinUpItem,
|
||||
liftItem,
|
||||
selectParentNodeItem,
|
||||
undoItem,
|
||||
redoItem,
|
||||
icons,
|
||||
MenuItem,
|
||||
MenuElement
|
||||
wrapItem,
|
||||
blockTypeItem,
|
||||
Dropdown,
|
||||
DropdownSubmenu,
|
||||
joinUpItem,
|
||||
liftItem,
|
||||
selectParentNodeItem,
|
||||
undoItem,
|
||||
redoItem,
|
||||
icons,
|
||||
MenuItem,
|
||||
MenuElement
|
||||
} = require("prosemirror-menu");
|
||||
var { NodeSelection, EditorState } = require("prosemirror-state");
|
||||
var { Schema, NodeType, MarkType } = require("prosemirror-model");
|
||||
@ -28,144 +28,144 @@ var { wrapInList } = require("prosemirror-flat-list");
|
||||
var { TextField, openPrompt } = require("$:/plugins/tiddlywiki/prosemirror/setup/prompt.js");
|
||||
|
||||
function canInsert(state, nodeType) {
|
||||
var $from = state.selection.$from;
|
||||
for (var d = $from.depth; d >= 0; d--) {
|
||||
var index = $from.index(d);
|
||||
if ($from.node(d).canReplaceWith(index, index, nodeType)) return true;
|
||||
}
|
||||
return false;
|
||||
var $from = state.selection.$from;
|
||||
for (var d = $from.depth; d >= 0; d--) {
|
||||
var index = $from.index(d);
|
||||
if ($from.node(d).canReplaceWith(index, index, nodeType)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function insertImageItem(nodeType) {
|
||||
return new MenuItem({
|
||||
title: "Insert image",
|
||||
label: "Image",
|
||||
enable: function(state) { return canInsert(state, nodeType); },
|
||||
run: function(state, _, view) {
|
||||
var from = state.selection.from, to = state.selection.to, attrs = null;
|
||||
if (state.selection instanceof NodeSelection && state.selection.node.type == nodeType)
|
||||
attrs = state.selection.node.attrs;
|
||||
openPrompt({
|
||||
title: "Insert image",
|
||||
fields: {
|
||||
src: new TextField({label: "Location", required: true, value: attrs && attrs.src}),
|
||||
title: new TextField({label: "Title", value: attrs && attrs.title}),
|
||||
alt: new TextField({label: "Description", value: attrs ? attrs.alt : state.doc.textBetween(from, to, " ")})
|
||||
},
|
||||
callback: function(attrs) {
|
||||
view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)));
|
||||
view.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return new MenuItem({
|
||||
title: "Insert image",
|
||||
label: "Image",
|
||||
enable: function(state) { return canInsert(state, nodeType); },
|
||||
run: function(state, _, view) {
|
||||
var from = state.selection.from, to = state.selection.to, attrs = null;
|
||||
if (state.selection instanceof NodeSelection && state.selection.node.type == nodeType)
|
||||
attrs = state.selection.node.attrs;
|
||||
openPrompt({
|
||||
title: "Insert image",
|
||||
fields: {
|
||||
src: new TextField({label: "Location", required: true, value: attrs && attrs.src}),
|
||||
title: new TextField({label: "Title", value: attrs && attrs.title}),
|
||||
alt: new TextField({label: "Description", value: attrs ? attrs.alt : state.doc.textBetween(from, to, " ")})
|
||||
},
|
||||
callback: function(attrs) {
|
||||
view.dispatch(view.state.tr.replaceSelectionWith(nodeType.createAndFill(attrs)));
|
||||
view.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cmdItem(cmd, options) {
|
||||
var passedOptions = {
|
||||
label: options.title,
|
||||
run: cmd
|
||||
};
|
||||
for (var prop in options) passedOptions[prop] = options[prop];
|
||||
if (!options.enable && !options.select)
|
||||
passedOptions[options.enable ? "enable" : "select"] = function(state) { return cmd(state); };
|
||||
var passedOptions = {
|
||||
label: options.title,
|
||||
run: cmd
|
||||
};
|
||||
for (var prop in options) passedOptions[prop] = options[prop];
|
||||
if (!options.enable && !options.select)
|
||||
passedOptions[options.enable ? "enable" : "select"] = function(state) { return cmd(state); };
|
||||
|
||||
return new MenuItem(passedOptions);
|
||||
return new MenuItem(passedOptions);
|
||||
}
|
||||
|
||||
function markActive(state, type) {
|
||||
var from = state.selection.from, $from = state.selection.$from, to = state.selection.to, empty = state.selection.empty;
|
||||
if (empty) return !!type.isInSet(state.storedMarks || $from.marks());
|
||||
else return state.doc.rangeHasMark(from, to, type);
|
||||
var from = state.selection.from, $from = state.selection.$from, to = state.selection.to, empty = state.selection.empty;
|
||||
if (empty) return !!type.isInSet(state.storedMarks || $from.marks());
|
||||
else return state.doc.rangeHasMark(from, to, type);
|
||||
}
|
||||
|
||||
function markItem(markType, options) {
|
||||
var passedOptions = {
|
||||
active: function(state) { return markActive(state, markType); }
|
||||
};
|
||||
for (var prop in options) passedOptions[prop] = options[prop];
|
||||
return cmdItem(toggleMark(markType), passedOptions);
|
||||
var passedOptions = {
|
||||
active: function(state) { return markActive(state, markType); }
|
||||
};
|
||||
for (var prop in options) passedOptions[prop] = options[prop];
|
||||
return cmdItem(toggleMark(markType), passedOptions);
|
||||
}
|
||||
|
||||
function linkItem(markType) {
|
||||
return new MenuItem({
|
||||
title: "Add or remove link",
|
||||
icon: icons.link,
|
||||
active: function(state) { return markActive(state, markType); },
|
||||
enable: function(state) { return !state.selection.empty; },
|
||||
run: function(state, dispatch, view) {
|
||||
if (markActive(state, markType)) {
|
||||
toggleMark(markType)(state, dispatch);
|
||||
return true;
|
||||
}
|
||||
openPrompt({
|
||||
title: "Create a link",
|
||||
fields: {
|
||||
href: new TextField({label: "Link target", required: true}),
|
||||
title: new TextField({label: "Title"})
|
||||
},
|
||||
callback: function(attrs) {
|
||||
toggleMark(markType, attrs)(view.state, view.dispatch);
|
||||
view.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return new MenuItem({
|
||||
title: "Add or remove link",
|
||||
icon: icons.link,
|
||||
active: function(state) { return markActive(state, markType); },
|
||||
enable: function(state) { return !state.selection.empty; },
|
||||
run: function(state, dispatch, view) {
|
||||
if (markActive(state, markType)) {
|
||||
toggleMark(markType)(state, dispatch);
|
||||
return true;
|
||||
}
|
||||
openPrompt({
|
||||
title: "Create a link",
|
||||
fields: {
|
||||
href: new TextField({label: "Link target", required: true}),
|
||||
title: new TextField({label: "Title"})
|
||||
},
|
||||
callback: function(attrs) {
|
||||
toggleMark(markType, attrs)(view.state, view.dispatch);
|
||||
view.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function wrapListItem(nodeType, options) {
|
||||
return cmdItem(wrapInList(nodeType, options.attrs), options);
|
||||
return cmdItem(wrapInList(nodeType, options.attrs), options);
|
||||
}
|
||||
|
||||
function buildMenuItems(schema) {
|
||||
var r = {};
|
||||
var mark;
|
||||
if (mark = schema.marks.strong)
|
||||
r.toggleStrong = markItem(mark, {title: "Toggle strong style", icon: icons.strong});
|
||||
if (mark = schema.marks.em)
|
||||
r.toggleEm = markItem(mark, {title: "Toggle emphasis", icon: icons.em});
|
||||
if (mark = schema.marks.code)
|
||||
r.toggleCode = markItem(mark, {title: "Toggle code font", icon: icons.code});
|
||||
if (mark = schema.marks.link)
|
||||
r.toggleLink = linkItem(mark);
|
||||
var r = {};
|
||||
var mark;
|
||||
if (mark = schema.marks.strong)
|
||||
r.toggleStrong = markItem(mark, {title: "Toggle strong style", icon: icons.strong});
|
||||
if (mark = schema.marks.em)
|
||||
r.toggleEm = markItem(mark, {title: "Toggle emphasis", icon: icons.em});
|
||||
if (mark = schema.marks.code)
|
||||
r.toggleCode = markItem(mark, {title: "Toggle code font", icon: icons.code});
|
||||
if (mark = schema.marks.link)
|
||||
r.toggleLink = linkItem(mark);
|
||||
|
||||
var node;
|
||||
if (node = schema.nodes.image)
|
||||
r.insertImage = insertImageItem(node);
|
||||
if (node = schema.nodes.bullet_list)
|
||||
r.wrapBulletList = wrapListItem(node, {title: "Wrap in bullet list", icon: icons.bulletList});
|
||||
if (node = schema.nodes.ordered_list)
|
||||
r.wrapOrderedList = wrapListItem(node, {title: "Wrap in ordered list", icon: icons.orderedList});
|
||||
if (node = schema.nodes.blockquote)
|
||||
r.wrapBlockQuote = wrapItem(node, {title: "Wrap in block quote", icon: icons.blockquote});
|
||||
if (node = schema.nodes.paragraph)
|
||||
r.makeParagraph = blockTypeItem(node, {title: "Change to paragraph", label: "Plain"});
|
||||
if (node = schema.nodes.code_block)
|
||||
r.makeCodeBlock = blockTypeItem(node, {title: "Change to code block", label: "Code"});
|
||||
if (node = schema.nodes.heading)
|
||||
for (var i = 1; i <= 10; i++)
|
||||
r["makeHead" + i] = blockTypeItem(node, {title: "Change to heading " + i, label: "Level " + i, attrs: {level: i}});
|
||||
if (node = schema.nodes.horizontal_rule) {
|
||||
var hr = node;
|
||||
r.insertHorizontalRule = new MenuItem({
|
||||
title: "Insert horizontal rule",
|
||||
label: "Horizontal rule",
|
||||
enable: function(state) { return canInsert(state, hr); },
|
||||
run: function(state, dispatch) { dispatch(state.tr.replaceSelectionWith(hr.create())); }
|
||||
});
|
||||
}
|
||||
var node;
|
||||
if (node = schema.nodes.image)
|
||||
r.insertImage = insertImageItem(node);
|
||||
if (node = schema.nodes.bullet_list)
|
||||
r.wrapBulletList = wrapListItem(node, {title: "Wrap in bullet list", icon: icons.bulletList});
|
||||
if (node = schema.nodes.ordered_list)
|
||||
r.wrapOrderedList = wrapListItem(node, {title: "Wrap in ordered list", icon: icons.orderedList});
|
||||
if (node = schema.nodes.blockquote)
|
||||
r.wrapBlockQuote = wrapItem(node, {title: "Wrap in block quote", icon: icons.blockquote});
|
||||
if (node = schema.nodes.paragraph)
|
||||
r.makeParagraph = blockTypeItem(node, {title: "Change to paragraph", label: "Plain"});
|
||||
if (node = schema.nodes.code_block)
|
||||
r.makeCodeBlock = blockTypeItem(node, {title: "Change to code block", label: "Code"});
|
||||
if (node = schema.nodes.heading)
|
||||
for (var i = 1; i <= 10; i++)
|
||||
r["makeHead" + i] = blockTypeItem(node, {title: "Change to heading " + i, label: "Level " + i, attrs: {level: i}});
|
||||
if (node = schema.nodes.horizontal_rule) {
|
||||
var hr = node;
|
||||
r.insertHorizontalRule = new MenuItem({
|
||||
title: "Insert horizontal rule",
|
||||
label: "Horizontal rule",
|
||||
enable: function(state) { return canInsert(state, hr); },
|
||||
run: function(state, dispatch) { dispatch(state.tr.replaceSelectionWith(hr.create())); }
|
||||
});
|
||||
}
|
||||
|
||||
var cut = function(arr) { return arr.filter(function(x) { return x; }); };
|
||||
r.insertMenu = new Dropdown(cut([r.insertImage, r.insertHorizontalRule]), {label: "Insert"});
|
||||
r.typeMenu = new Dropdown(cut([r.makeParagraph, r.makeCodeBlock, r.makeHead1 && new DropdownSubmenu(cut([
|
||||
r.makeHead1, r.makeHead2, r.makeHead3, r.makeHead4, r.makeHead5, r.makeHead6
|
||||
]), {label: "Heading"})]), {label: "Type..."});
|
||||
var cut = function(arr) { return arr.filter(function(x) { return x; }); };
|
||||
r.insertMenu = new Dropdown(cut([r.insertImage, r.insertHorizontalRule]), {label: "Insert"});
|
||||
r.typeMenu = new Dropdown(cut([r.makeParagraph, r.makeCodeBlock, r.makeHead1 && new DropdownSubmenu(cut([
|
||||
r.makeHead1, r.makeHead2, r.makeHead3, r.makeHead4, r.makeHead5, r.makeHead6
|
||||
]), {label: "Heading"})]), {label: "Type..."});
|
||||
|
||||
r.inlineMenu = [cut([r.toggleStrong, r.toggleEm, r.toggleCode, r.toggleLink])];
|
||||
r.blockMenu = [cut([r.wrapBulletList, r.wrapOrderedList, r.wrapBlockQuote, joinUpItem, liftItem, selectParentNodeItem])];
|
||||
r.fullMenu = r.inlineMenu.concat([[r.insertMenu, r.typeMenu]], [[undoItem, redoItem]], r.blockMenu);
|
||||
r.inlineMenu = [cut([r.toggleStrong, r.toggleEm, r.toggleCode, r.toggleLink])];
|
||||
r.blockMenu = [cut([r.wrapBulletList, r.wrapOrderedList, r.wrapBlockQuote, joinUpItem, liftItem, selectParentNodeItem])];
|
||||
r.fullMenu = r.inlineMenu.concat([[r.insertMenu, r.typeMenu]], [[undoItem, redoItem]], r.blockMenu);
|
||||
|
||||
return r;
|
||||
return r;
|
||||
}
|
||||
|
||||
exports.buildMenuItems = buildMenuItems;
|
||||
|
@ -12,101 +12,101 @@ var { Attrs } = require("prosemirror-model");
|
||||
var prefix = "ProseMirror-prompt";
|
||||
|
||||
function openPrompt(options) {
|
||||
var wrapper = document.body.appendChild(document.createElement("div"));
|
||||
wrapper.className = prefix;
|
||||
var wrapper = document.body.appendChild(document.createElement("div"));
|
||||
wrapper.className = prefix;
|
||||
|
||||
var mouseOutside = function(e) { if (!wrapper.contains(e.target)) close(); };
|
||||
setTimeout(function() { window.addEventListener("mousedown", mouseOutside); }, 50);
|
||||
var close = function() {
|
||||
window.removeEventListener("mousedown", mouseOutside);
|
||||
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
|
||||
};
|
||||
var mouseOutside = function(e) { if (!wrapper.contains(e.target)) close(); };
|
||||
setTimeout(function() { window.addEventListener("mousedown", mouseOutside); }, 50);
|
||||
var close = function() {
|
||||
window.removeEventListener("mousedown", mouseOutside);
|
||||
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
|
||||
};
|
||||
|
||||
var domFields = [];
|
||||
for (var name in options.fields) domFields.push(options.fields[name].render());
|
||||
var domFields = [];
|
||||
for (var name in options.fields) domFields.push(options.fields[name].render());
|
||||
|
||||
var submitButton = document.createElement("button");
|
||||
submitButton.type = "submit";
|
||||
submitButton.className = prefix + "-submit";
|
||||
submitButton.textContent = "OK";
|
||||
var cancelButton = document.createElement("button");
|
||||
cancelButton.type = "button";
|
||||
cancelButton.className = prefix + "-cancel";
|
||||
cancelButton.textContent = "Cancel";
|
||||
cancelButton.addEventListener("click", close);
|
||||
var submitButton = document.createElement("button");
|
||||
submitButton.type = "submit";
|
||||
submitButton.className = prefix + "-submit";
|
||||
submitButton.textContent = "OK";
|
||||
var cancelButton = document.createElement("button");
|
||||
cancelButton.type = "button";
|
||||
cancelButton.className = prefix + "-cancel";
|
||||
cancelButton.textContent = "Cancel";
|
||||
cancelButton.addEventListener("click", close);
|
||||
|
||||
var form = wrapper.appendChild(document.createElement("form"));
|
||||
if (options.title) form.appendChild(document.createElement("h5")).textContent = options.title;
|
||||
domFields.forEach(function(field) {
|
||||
form.appendChild(document.createElement("div")).appendChild(field);
|
||||
});
|
||||
var buttons = form.appendChild(document.createElement("div"));
|
||||
buttons.className = prefix + "-buttons";
|
||||
buttons.appendChild(submitButton);
|
||||
buttons.appendChild(document.createTextNode(" "));
|
||||
buttons.appendChild(cancelButton);
|
||||
var form = wrapper.appendChild(document.createElement("form"));
|
||||
if (options.title) form.appendChild(document.createElement("h5")).textContent = options.title;
|
||||
domFields.forEach(function(field) {
|
||||
form.appendChild(document.createElement("div")).appendChild(field);
|
||||
});
|
||||
var buttons = form.appendChild(document.createElement("div"));
|
||||
buttons.className = prefix + "-buttons";
|
||||
buttons.appendChild(submitButton);
|
||||
buttons.appendChild(document.createTextNode(" "));
|
||||
buttons.appendChild(cancelButton);
|
||||
|
||||
var box = wrapper.getBoundingClientRect();
|
||||
wrapper.style.top = ((window.innerHeight - box.height) / 2) + "px";
|
||||
wrapper.style.left = ((window.innerWidth - box.width) / 2) + "px";
|
||||
var box = wrapper.getBoundingClientRect();
|
||||
wrapper.style.top = ((window.innerHeight - box.height) / 2) + "px";
|
||||
wrapper.style.left = ((window.innerWidth - box.width) / 2) + "px";
|
||||
|
||||
var submit = function() {
|
||||
var params = getValues(options.fields, domFields);
|
||||
if (params) {
|
||||
close();
|
||||
options.callback(params);
|
||||
}
|
||||
};
|
||||
var submit = function() {
|
||||
var params = getValues(options.fields, domFields);
|
||||
if (params) {
|
||||
close();
|
||||
options.callback(params);
|
||||
}
|
||||
};
|
||||
|
||||
form.addEventListener("submit", function(e) {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
});
|
||||
form.addEventListener("submit", function(e) {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
});
|
||||
|
||||
form.addEventListener("keydown", function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
e.preventDefault();
|
||||
close();
|
||||
} else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
} else if (e.keyCode == 9) {
|
||||
window.setTimeout(function() {
|
||||
if (!wrapper.contains(document.activeElement)) close();
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
form.addEventListener("keydown", function(e) {
|
||||
if (e.keyCode == 27) {
|
||||
e.preventDefault();
|
||||
close();
|
||||
} else if (e.keyCode == 13 && !(e.ctrlKey || e.metaKey || e.shiftKey)) {
|
||||
e.preventDefault();
|
||||
submit();
|
||||
} else if (e.keyCode == 9) {
|
||||
window.setTimeout(function() {
|
||||
if (!wrapper.contains(document.activeElement)) close();
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
|
||||
var input = form.elements[0];
|
||||
if (input) input.focus();
|
||||
var input = form.elements[0];
|
||||
if (input) input.focus();
|
||||
}
|
||||
|
||||
function getValues(fields, domFields) {
|
||||
var result = Object.create(null), i = 0;
|
||||
for (var name in fields) {
|
||||
var field = fields[name], dom = domFields[i++];
|
||||
var value = field.read(dom), bad = field.validate(value);
|
||||
if (bad) {
|
||||
reportInvalid(dom, bad);
|
||||
return null;
|
||||
}
|
||||
result[name] = field.clean(value);
|
||||
}
|
||||
return result;
|
||||
var result = Object.create(null), i = 0;
|
||||
for (var name in fields) {
|
||||
var field = fields[name], dom = domFields[i++];
|
||||
var value = field.read(dom), bad = field.validate(value);
|
||||
if (bad) {
|
||||
reportInvalid(dom, bad);
|
||||
return null;
|
||||
}
|
||||
result[name] = field.clean(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function reportInvalid(dom, message) {
|
||||
var parent = dom.parentNode;
|
||||
var msg = parent.appendChild(document.createElement("div"));
|
||||
msg.style.left = (dom.offsetLeft + dom.offsetWidth + 2) + "px";
|
||||
msg.style.top = (dom.offsetTop - 5) + "px";
|
||||
msg.className = "ProseMirror-invalid";
|
||||
msg.textContent = message;
|
||||
setTimeout(function() { parent.removeChild(msg); }, 1500);
|
||||
var parent = dom.parentNode;
|
||||
var msg = parent.appendChild(document.createElement("div"));
|
||||
msg.style.left = (dom.offsetLeft + dom.offsetWidth + 2) + "px";
|
||||
msg.style.top = (dom.offsetTop - 5) + "px";
|
||||
msg.className = "ProseMirror-invalid";
|
||||
msg.textContent = message;
|
||||
setTimeout(function() { parent.removeChild(msg); }, 1500);
|
||||
}
|
||||
|
||||
function Field(options) {
|
||||
this.options = options;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
Field.prototype.read = function(dom) { return dom.value; };
|
||||
@ -114,45 +114,45 @@ Field.prototype.read = function(dom) { return dom.value; };
|
||||
Field.prototype.validateType = function(value) { return null; };
|
||||
|
||||
Field.prototype.validate = function(value) {
|
||||
if (!value && this.options.required)
|
||||
return "Required field";
|
||||
return this.validateType(value) || (this.options.validate ? this.options.validate(value) : null);
|
||||
if (!value && this.options.required)
|
||||
return "Required field";
|
||||
return this.validateType(value) || (this.options.validate ? this.options.validate(value) : null);
|
||||
};
|
||||
|
||||
Field.prototype.clean = function(value) {
|
||||
return this.options.clean ? this.options.clean(value) : value;
|
||||
return this.options.clean ? this.options.clean(value) : value;
|
||||
};
|
||||
|
||||
function TextField(options) {
|
||||
Field.call(this, options);
|
||||
Field.call(this, options);
|
||||
}
|
||||
|
||||
TextField.prototype = Object.create(Field.prototype);
|
||||
|
||||
TextField.prototype.render = function() {
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = this.options.label;
|
||||
input.value = this.options.value || "";
|
||||
input.autocomplete = "off";
|
||||
return input;
|
||||
var input = document.createElement("input");
|
||||
input.type = "text";
|
||||
input.placeholder = this.options.label;
|
||||
input.value = this.options.value || "";
|
||||
input.autocomplete = "off";
|
||||
return input;
|
||||
};
|
||||
|
||||
function SelectField(options) {
|
||||
Field.call(this, options);
|
||||
Field.call(this, options);
|
||||
}
|
||||
|
||||
SelectField.prototype = Object.create(Field.prototype);
|
||||
|
||||
SelectField.prototype.render = function() {
|
||||
var select = document.createElement("select");
|
||||
this.options.options.forEach(function(o) {
|
||||
var opt = select.appendChild(document.createElement("option"));
|
||||
opt.value = o.value;
|
||||
opt.selected = o.value == this.options.value;
|
||||
opt.label = o.label;
|
||||
}, this);
|
||||
return select;
|
||||
var select = document.createElement("select");
|
||||
this.options.options.forEach(function(o) {
|
||||
var opt = select.appendChild(document.createElement("option"));
|
||||
opt.value = o.value;
|
||||
opt.selected = o.value == this.options.value;
|
||||
opt.label = o.label;
|
||||
}, this);
|
||||
return select;
|
||||
};
|
||||
|
||||
exports.openPrompt = openPrompt;
|
||||
|
@ -25,23 +25,23 @@ exports.buildKeymap = buildKeymap;
|
||||
exports.buildInputRules = buildInputRules;
|
||||
|
||||
function exampleSetup(options) {
|
||||
var plugins = [
|
||||
buildInputRules(options.schema),
|
||||
keymap(buildKeymap(options.schema, options.mapKeys)),
|
||||
keymap(baseKeymap),
|
||||
dropCursor(),
|
||||
gapCursor()
|
||||
];
|
||||
if (options.menuBar !== false)
|
||||
plugins.push(menuBar({ floating: options.floatingMenu !== false, content: options.menuContent || buildMenuItems(options.schema).fullMenu }));
|
||||
if (options.history !== false)
|
||||
plugins.push(history());
|
||||
var plugins = [
|
||||
buildInputRules(options.schema),
|
||||
keymap(buildKeymap(options.schema, options.mapKeys)),
|
||||
keymap(baseKeymap),
|
||||
dropCursor(),
|
||||
gapCursor()
|
||||
];
|
||||
if (options.menuBar !== false)
|
||||
plugins.push(menuBar({ floating: options.floatingMenu !== false, content: options.menuContent || buildMenuItems(options.schema).fullMenu }));
|
||||
if (options.history !== false)
|
||||
plugins.push(history());
|
||||
|
||||
return plugins.concat(new Plugin({
|
||||
props: {
|
||||
attributes: { class: "ProseMirror-example-setup-style" }
|
||||
}
|
||||
}));
|
||||
return plugins.concat(new Plugin({
|
||||
props: {
|
||||
attributes: { class: "ProseMirror-example-setup-style" }
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
exports.exampleSetup = exampleSetup;
|
||||
|
@ -6,7 +6,7 @@ module-type: widget
|
||||
\*/
|
||||
|
||||
if (!$tw.browser) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
// separate the widget from the exports here, so we can skip the require of react code if `!$tw.browser`. Those ts code will error if loaded in the nodejs side.
|
||||
const components = require('$:/plugins/tiddlywiki/prosemirror/widget.js');
|
||||
|
@ -17,10 +17,10 @@ var { EditorView } = require("prosemirror-view");
|
||||
var { Schema, DOMParser } = require("prosemirror-model");
|
||||
var { schema: basicSchema } = require("prosemirror-schema-basic");
|
||||
var {
|
||||
createListPlugins,
|
||||
createListSpec,
|
||||
listInputRules,
|
||||
listKeymap
|
||||
createListPlugins,
|
||||
createListSpec,
|
||||
listInputRules,
|
||||
listKeymap
|
||||
} = require("prosemirror-flat-list");
|
||||
var { exampleSetup } = require("$:/plugins/tiddlywiki/prosemirror/setup/setup.js");
|
||||
var { keymap } = require("prosemirror-keymap");
|
||||
@ -43,58 +43,58 @@ ProsemirrorWidget.prototype.render = function(parent,nextSibling) {
|
||||
this.computeAttributes();
|
||||
this.execute();
|
||||
|
||||
var tiddler = this.getAttribute("tiddler");
|
||||
var initialText = this.wiki.getTiddlerText(tiddler, "");
|
||||
var initialWikiAst = $tw.wiki.parseText(null, initialText).tree;
|
||||
var doc = wikiAstToProseMirrorAst(initialWikiAst);
|
||||
// DEBUG: console doc
|
||||
console.log(`initial doc`, doc);
|
||||
var tiddler = this.getAttribute("tiddler");
|
||||
var initialText = this.wiki.getTiddlerText(tiddler, "");
|
||||
var initialWikiAst = $tw.wiki.parseText(null, initialText).tree;
|
||||
var doc = wikiAstToProseMirrorAst(initialWikiAst);
|
||||
// DEBUG: console doc
|
||||
console.log(`initial doc`, doc);
|
||||
|
||||
var container = $tw.utils.domMaker('div', {
|
||||
class: 'tc-prosemirror-container',
|
||||
});
|
||||
|
||||
var schema = new Schema({
|
||||
nodes: basicSchema.spec.nodes.append({ list: createListSpec() }),
|
||||
marks: basicSchema.spec.marks,
|
||||
})
|
||||
|
||||
var listKeymapPlugin = keymap(listKeymap)
|
||||
var listInputRulePlugin = inputRules({ rules: listInputRules })
|
||||
var listPlugins = createListPlugins({ schema })
|
||||
var container = $tw.utils.domMaker('div', {
|
||||
class: 'tc-prosemirror-container',
|
||||
});
|
||||
|
||||
var schema = new Schema({
|
||||
nodes: basicSchema.spec.nodes.append({ list: createListSpec() }),
|
||||
marks: basicSchema.spec.marks,
|
||||
})
|
||||
|
||||
var listKeymapPlugin = keymap(listKeymap)
|
||||
var listInputRulePlugin = inputRules({ rules: listInputRules })
|
||||
var listPlugins = createListPlugins({ schema })
|
||||
|
||||
var self = this;
|
||||
this.view = new EditorView(container, {
|
||||
state: EditorState.create({
|
||||
// doc: schema.node("doc", null, [schema.node("paragraph")]),
|
||||
doc: schema.nodeFromJSON(doc),
|
||||
plugins: [
|
||||
listKeymapPlugin,
|
||||
listInputRulePlugin,
|
||||
...listPlugins,
|
||||
...exampleSetup({ schema }),
|
||||
],
|
||||
}),
|
||||
dispatchTransaction: function(transaction) {
|
||||
var newState = self.view.state.apply(transaction);
|
||||
self.view.updateState(newState);
|
||||
self.debouncedSaveEditorContent();
|
||||
}
|
||||
})
|
||||
|
||||
var self = this;
|
||||
this.view = new EditorView(container, {
|
||||
state: EditorState.create({
|
||||
// doc: schema.node("doc", null, [schema.node("paragraph")]),
|
||||
doc: schema.nodeFromJSON(doc),
|
||||
plugins: [
|
||||
listKeymapPlugin,
|
||||
listInputRulePlugin,
|
||||
...listPlugins,
|
||||
...exampleSetup({ schema }),
|
||||
],
|
||||
}),
|
||||
dispatchTransaction: function(transaction) {
|
||||
var newState = self.view.state.apply(transaction);
|
||||
self.view.updateState(newState);
|
||||
self.debouncedSaveEditorContent();
|
||||
}
|
||||
})
|
||||
|
||||
parent.insertBefore(container,nextSibling);
|
||||
this.domNodes.push(container);
|
||||
};
|
||||
|
||||
ProsemirrorWidget.prototype.saveEditorContent = function() {
|
||||
var content = this.view.state.doc.toJSON();
|
||||
console.log(`ProseMirror: ${JSON.stringify(content)}`, content);
|
||||
var wikiast = wikiAstFromProseMirrorAst(content);
|
||||
console.log(`WikiAST: ${JSON.stringify(wikiast)}`, wikiast);
|
||||
var wikiText = $tw.utils.serializeParseTree(wikiast);
|
||||
console.log(`WikiText: ${wikiText}`);
|
||||
var tiddler = this.getAttribute("tiddler");
|
||||
this.wiki.setText(tiddler, "text", undefined, wikiText);
|
||||
var content = this.view.state.doc.toJSON();
|
||||
console.log(`ProseMirror: ${JSON.stringify(content)}`, content);
|
||||
var wikiast = wikiAstFromProseMirrorAst(content);
|
||||
console.log(`WikiAST: ${JSON.stringify(wikiast)}`, wikiast);
|
||||
var wikiText = $tw.utils.serializeParseTree(wikiast);
|
||||
console.log(`WikiText: ${wikiText}`);
|
||||
var tiddler = this.getAttribute("tiddler");
|
||||
this.wiki.setText(tiddler, "text", undefined, wikiText);
|
||||
}
|
||||
|
||||
// Debounced save function for performance
|
||||
|
Loading…
x
Reference in New Issue
Block a user