mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-12 12:40:08 +08:00
7b18f43eab
Summary: - Include ES6 files in spec-suite - Fix template store specs - Refactors TemplateStore a little bit to adjust to specs - Convert coffe .cjsx files to ES6 .jsx files - Fix TemplateDraftStoreExtension functions - Update ComposerTemplates example README Test Plan: - Plugin unit tests Reviewers: bengotow, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2250
129 lines
3.9 KiB
JavaScript
129 lines
3.9 KiB
JavaScript
import {DraftStoreExtension} from 'nylas-exports';
|
|
|
|
class TemplatesDraftStoreExtension extends DraftStoreExtension {
|
|
|
|
static warningsForSending(draft) {
|
|
const warnings = [];
|
|
if (draft.body.search(/<code[^>]*empty[^>]*>/i) > 0) {
|
|
warnings.push('with an empty template area');
|
|
}
|
|
return warnings;
|
|
}
|
|
|
|
static finalizeSessionBeforeSending(session) {
|
|
const body = session.draft().body;
|
|
const clean = body.replace(/<\/?code[^>]*>/g, '');
|
|
if (body !== clean) {
|
|
return session.changes.add({body: clean});
|
|
}
|
|
}
|
|
|
|
static onMouseUp(editableNode, range) {
|
|
const ref = range.startContainer;
|
|
let parent = (ref != null) ? ref.parentNode : undefined;
|
|
let parentCodeNode = null;
|
|
|
|
while (parent && parent !== editableNode) {
|
|
const ref1 = parent.classList;
|
|
if (((ref1 != null) ? ref1.contains('var') : undefined) && parent.tagName === 'CODE') {
|
|
parentCodeNode = parent;
|
|
break;
|
|
}
|
|
parent = parent.parentNode;
|
|
}
|
|
|
|
const isSinglePoint = range.startContainer === range.endContainer && range.startOffset === range.endOffset;
|
|
|
|
if (isSinglePoint && parentCodeNode) {
|
|
range.selectNode(parentCodeNode);
|
|
const selection = document.getSelection();
|
|
selection.removeAllRanges();
|
|
return selection.addRange(range);
|
|
}
|
|
}
|
|
|
|
static onTabDown(editableNode, range, event) {
|
|
console.log('tabbed');
|
|
if (event.shiftKey) {
|
|
return this.onTabSelectNextVar(editableNode, range, event, -1);
|
|
}
|
|
return this.onTabSelectNextVar(editableNode, range, event, 1);
|
|
}
|
|
|
|
static onTabSelectNextVar(editableNode, range, event, delta) {
|
|
if (!range) { return; }
|
|
|
|
// Try to find the node that the selection range is
|
|
// currently intersecting with (inside, or around)
|
|
let parentCodeNode = null;
|
|
const nodes = editableNode.querySelectorAll('code.var');
|
|
for (let i = 0, node; i < nodes.length; i++) {
|
|
node = nodes[i];
|
|
if (range.intersectsNode(node)) {
|
|
parentCodeNode = node;
|
|
}
|
|
}
|
|
|
|
let selectNode = null;
|
|
if (parentCodeNode) {
|
|
if (range.startOffset === range.endOffset && parentCodeNode.classList.contains('empty')) {
|
|
// If the current node is empty and it's a single insertion point,
|
|
// select the current node rather than advancing to the next node
|
|
selectNode = parentCodeNode;
|
|
} else {
|
|
// advance to the next code node
|
|
const matches = editableNode.querySelectorAll('code.var');
|
|
let matchIndex = -1;
|
|
for (let idx = 0, match; idx < matches.length; idx++) {
|
|
match = matches[idx];
|
|
if (match === parentCodeNode) {
|
|
matchIndex = idx;
|
|
break;
|
|
}
|
|
}
|
|
if (matchIndex !== -1 && matchIndex + delta >= 0 && matchIndex + delta < matches.length) {
|
|
selectNode = matches[matchIndex + delta];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selectNode) {
|
|
range.selectNode(selectNode);
|
|
const selection = document.getSelection();
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
}
|
|
}
|
|
|
|
static onInput(editableNode) {
|
|
const selection = document.getSelection();
|
|
|
|
const isWithinNode = (node)=> {
|
|
let test = selection.baseNode;
|
|
while (test !== editableNode) {
|
|
if (test === node) { return true; }
|
|
test = test.parentNode;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
const codeTags = editableNode.querySelectorAll('code.var.empty');
|
|
return (() => {
|
|
const result = [];
|
|
for (let i = 0, codeTag; i < codeTags.length; i++) {
|
|
codeTag = codeTags[i];
|
|
result.push((() => {
|
|
if (selection.containsNode(codeTag) || isWithinNode(codeTag)) {
|
|
return codeTag.classList.remove('empty');
|
|
}
|
|
})());
|
|
}
|
|
return result;
|
|
})();
|
|
}
|
|
}
|
|
|
|
|
|
module.exports = TemplatesDraftStoreExtension;
|