slate-edit-code
Version:
A Slate plugin to handle code blocks editing.
1,772 lines (1,437 loc) • 1.67 MB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require('react');
var ReactDOM = require('react-dom');
var Slate = require('slate');
var PluginEditCode = require('../lib/');
var stateJson = require('./state');
var plugin = PluginEditCode();
var plugins = [plugin];
var SCHEMA = {
nodes: {
code_block: function code_block(props) {
return React.createElement(
'div',
_extends({ className: 'code' }, props.attributes),
props.children
);
},
code_line: function code_line(props) {
return React.createElement(
'pre',
props.attributes,
props.children
);
},
paragraph: function paragraph(props) {
return React.createElement(
'p',
props.attributes,
props.children
);
},
heading: function heading(props) {
return React.createElement(
'h1',
props.attributes,
props.children
);
}
}
};
var Example = React.createClass({
displayName: 'Example',
getInitialState: function getInitialState() {
return {
state: Slate.State.fromJSON(stateJson)
};
},
onChange: function onChange(_ref) {
var state = _ref.state;
this.setState({
state: state
});
},
onToggleCode: function onToggleCode() {
var state = this.state.state;
this.onChange(plugin.changes.toggleCodeBlock(state.change(), 'paragraph').focus());
},
render: function render() {
var state = this.state.state;
return React.createElement(
'div',
null,
React.createElement(
'button',
{ onClick: this.onToggleCode },
plugin.utils.isInCodeBlock(state) ? 'Paragraph' : 'Code Block'
),
React.createElement(Slate.Editor, {
placeholder: 'Enter some text...',
plugins: plugins,
state: state,
onChange: this.onChange,
schema: SCHEMA
})
);
}
});
ReactDOM.render(React.createElement(Example, null), document.getElementById('example'));
},{"../lib/":14,"./state":2,"react":309,"react-dom":153,"slate":330}],2:[function(require,module,exports){
module.exports={
"document": {
"nodes": [
{
"kind": "block",
"type": "heading",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "Slate + Code Edition"
}
]
}
]
},
{
"kind": "block",
"type": "paragraph",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "This page is a basic example of Slate + slate-edit-code plugin. Press Tab to indent code. Shift+Tab to unindent. Press Enter to carry indentation onto the newline. Press Mod (Cmd on Mac, Ctrl on Windows) + Enter to exit the code block."
}
]
}
]
},
{
"kind": "block",
"type": "code_block",
"nodes": [
{
"kind": "block",
"type": "code_line",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "// Some JavaScript"
}
]
}
]
},
{
"kind": "block",
"type": "code_line",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "function hello() {"
}
]
}
]
},
{
"kind": "block",
"type": "code_line",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": " console.log('Hello World')"
}
]
}
]
},
{
"kind": "block",
"type": "code_line",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "}"
}
]
}
]
}
]
},
{
"kind": "block",
"type": "paragraph",
"nodes": [
{
"kind": "text",
"ranges": [
{
"text": "End paragraph"
}
]
}
]
}
]
}
}
},{}],3:[function(require,module,exports){
"use strict";
/**
* Dedent all lines in selection
* @param {Change} change
* @param {String} indent To remove
* @return {Change}
*/
function dedentLines(opts, change, indent) {
var state = change.state;
var document = state.document,
selection = state.selection;
var lines = document.getBlocksAtRange(selection).filter(function (node) {
return node.type === opts.lineType;
});
return lines.reduce(function (c, line) {
// Remove a level of indent from the start of line
var text = line.nodes.first();
var lengthToRemove = text.characters.takeWhile(function (char, index) {
return indent.charAt(index) === char.text;
}).count();
return c.removeTextByKey(text.key, 0, lengthToRemove);
}, change);
}
module.exports = dedentLines;
},{}],4:[function(require,module,exports){
"use strict";
/**
* Indent all lines in selection
* @param {Change} change
* @param {String} indent
* @return {Change}
*/
function indentLines(opts, change, indent) {
var state = change.state;
var document = state.document,
selection = state.selection;
var lines = document.getBlocksAtRange(selection).filter(function (node) {
return node.type === opts.lineType;
});
return lines.reduce(function (c, line) {
// Insert an indent at start of line
var text = line.nodes.first();
return c.insertTextByKey(text.key, 0, indent);
}, change);
}
module.exports = indentLines;
},{}],5:[function(require,module,exports){
'use strict';
var wrapCodeBlock = require('./wrapCodeBlock');
var unwrapCodeBlock = require('./unwrapCodeBlock');
var isInCodeBlock = require('../isInCodeBlock');
/**
* Toggle code block / paragraph.
* @param {Change} change
* @param {String} type
* @return {Change}
*/
function toggleCodeBlock(opts, change, type) {
if (isInCodeBlock(opts, change.state)) {
return unwrapCodeBlock(opts, change, type);
} else {
return wrapCodeBlock(opts, change);
}
}
module.exports = toggleCodeBlock;
},{"../isInCodeBlock":15,"./unwrapCodeBlock":6,"./wrapCodeBlock":8}],6:[function(require,module,exports){
'use strict';
var getCurrentCode = require('../getCurrentCode');
var unwrapCodeBlockByKey = require('./unwrapCodeBlockByKey');
/**
* Convert a code block to a normal block.
* @param {Change} change
* @param {String} type
* @return {Change}
*/
function unwrapCodeBlock(opts, change, type) {
var _change = change,
state = _change.state;
var codeBlock = getCurrentCode(opts, state);
if (!codeBlock) {
return change;
}
// Convert to paragraph
change = unwrapCodeBlockByKey(opts, change, codeBlock.key, type);
return change;
}
module.exports = unwrapCodeBlock;
},{"../getCurrentCode":11,"./unwrapCodeBlockByKey":7}],7:[function(require,module,exports){
'use strict';
/**
* Unwrap a code block into a normal block.
*
* @param {Change} change
* @param {String} key
* @param {String} type
* @return {Change}
*/
function unwrapCodeBlockByKey(opts, change, key, type) {
var state = change.state;
var document = state.document;
// Get the code block
var codeBlock = document.getDescendant(key);
if (!codeBlock || codeBlock.type != opts.containerType) {
throw new Error('Block passed to unwrapCodeBlockByKey should be a code block container');
}
// change lines into paragraph
codeBlock.nodes.forEach(function (line) {
return change.setNodeByKey(line.key, { type: type }).unwrapNodeByKey(line.key);
});
return change;
}
module.exports = unwrapCodeBlockByKey;
},{}],8:[function(require,module,exports){
'use strict';
var wrapCodeBlockByKey = require('./wrapCodeBlockByKey');
/**
* Wrap current block into a code block.
* @param {Change} change
* @return {Change}
*/
function wrapCodeBlock(opts, change) {
var _change = change,
state = _change.state;
var startBlock = state.startBlock,
selection = state.selection;
// Convert to code block
change = wrapCodeBlockByKey(opts, change, startBlock.key);
// Move selection back in the block
change.collapseToStartOf(change.state.document.getDescendant(startBlock.key)).moveOffsetsTo(selection.startOffset);
return change;
}
module.exports = wrapCodeBlock;
},{"./wrapCodeBlockByKey":9}],9:[function(require,module,exports){
'use strict';
var deserializeCode = require('../deserializeCode');
/**
* Wrap a block into a code block.
*
* @param {Change} change
* @param {String} key
* @return {Change}
*/
function wrapCodeBlockByKey(opts, change, key) {
var state = change.state;
var document = state.document;
var startBlock = document.getDescendant(key);
var text = startBlock.text;
// Remove all child
startBlock.nodes.forEach(function (node) {
change.removeNodeByKey(node.key, { normalize: false });
});
// Insert new text
var toInsert = deserializeCode(opts, text);
toInsert.nodes.forEach(function (node, i) {
change.insertNodeByKey(startBlock.key, i, node);
});
// Set node type
change.setNodeByKey(startBlock.key, {
type: opts.containerType
});
return change;
}
module.exports = wrapCodeBlockByKey;
},{"../deserializeCode":10}],10:[function(require,module,exports){
'use strict';
var _require = require('slate'),
Block = _require.Block,
Text = _require.Text;
var _require2 = require('immutable'),
List = _require2.List;
var detectNewline = require('detect-newline');
var DEFAULT_NEWLINE = '\n';
/**
* Deserialize a text into a code block
* @param {Option} opts
* @param {String} text
* @return {Block}
*/
function deserializeCode(opts, text) {
var sep = detectNewline(text) || DEFAULT_NEWLINE;
var lines = List(text.split(sep)).map(function (line) {
return Block.create({
type: opts.lineType,
nodes: [Text.create(line)]
});
});
var code = Block.create({
type: opts.containerType,
nodes: lines
});
return code;
}
module.exports = deserializeCode;
},{"detect-newline":25,"immutable":135,"slate":330}],11:[function(require,module,exports){
"use strict";
/**
* Return the current code block, from current selection or from a node key.
*
* @param {PluginOptions} opts
* @param {Slate.State} state
* @param {String} key?
* @return {Slate.Block || Void}
*/
function getCurrentCode(opts, state, key) {
var document = state.document;
var currentBlock = void 0;
if (key) {
currentBlock = state.document.getDescendant(key);
} else {
if (!state.selection.startKey) return null;
currentBlock = state.startBlock;
}
// The structure is always code_block -> code_line -> text
// So the parent of the currentBlock should be the code_block
var parent = document.getParent(currentBlock.key);
if (parent && parent.type === opts.containerType) {
return parent;
} else {
return null;
}
}
module.exports = getCurrentCode;
},{}],12:[function(require,module,exports){
'use strict';
var getIndent = require('./getIndent');
var getCurrentCode = require('./getCurrentCode');
/**
* Detect indentation in the current code block
* @param {Options} opts
* @param {State} state
* @return {String}
*/
function getCurrentIndent(opts, state) {
var currentCode = getCurrentCode(opts, state);
var text = currentCode.getTexts().map(function (t) {
return t.text;
}).join('\n');
return getIndent(text);
}
module.exports = getCurrentIndent;
},{"./getCurrentCode":11,"./getIndent":13}],13:[function(require,module,exports){
'use strict';
var detectIndent = require('detect-indent');
var DEFAULT_INDENTATION = ' ';
/**
* Detect indentation in a text
* @param {String} text
* @param {String} defaultValue?
* @return {String}
*/
function getIndent(text) {
var defaultValue = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : DEFAULT_INDENTATION;
return detectIndent(text).indent || defaultValue;
}
module.exports = getIndent;
},{"detect-indent":24}],14:[function(require,module,exports){
'use strict';
var _require = require('slate'),
Document = _require.Document;
var onEnter = require('./onEnter');
var onModEnter = require('./onModEnter');
var onTab = require('./onTab');
var onShiftTab = require('./onShiftTab');
var onBackspace = require('./onBackspace');
var onSelectAll = require('./onSelectAll');
var makeSchema = require('./makeSchema');
var getCurrentCode = require('./getCurrentCode');
var Options = require('./options');
var deserializeCode = require('./deserializeCode');
var isInCodeBlock = require('./isInCodeBlock');
var wrapCodeBlockByKey = require('./changes/wrapCodeBlockByKey');
var unwrapCodeBlockByKey = require('./changes/unwrapCodeBlockByKey');
var wrapCodeBlock = require('./changes/wrapCodeBlock');
var unwrapCodeBlock = require('./changes/unwrapCodeBlock');
var toggleCodeBlock = require('./changes/toggleCodeBlock');
var KEY_ENTER = 'enter';
var KEY_TAB = 'tab';
var KEY_BACKSPACE = 'backspace';
/**
* A Slate plugin to handle keyboard events in code blocks.
* @param {Options | Object} opts
* @return {Object}
*/
function EditCode(opts) {
opts = new Options(opts);
/**
* User is pressing a key in the editor
*/
function _onKeyDown(e, data, change) {
var state = change.state;
var currentCode = getCurrentCode(opts, state);
// Inside code ?
if (!currentCode) {
return;
}
// Add opts in the argument list
var args = [e, data, change, opts];
// Select all the code in the block (Mod+a)
if (data.key === 'a' && data.isMod && opts.selectAll) {
return onSelectAll.apply(undefined, args);
}
// User is pressing Shift+Tab
else if (data.key === KEY_TAB && data.isShift) {
return onShiftTab.apply(undefined, args);
}
// User is pressing Tab
else if (data.key == KEY_TAB) {
return onTab.apply(undefined, args);
}
// User is pressing Shift+Enter
else if (data.key == KEY_ENTER && data.isMod && opts.exitBlockType) {
return onModEnter.apply(undefined, args);
}
// User is pressing Enter
else if (data.key == KEY_ENTER) {
return onEnter.apply(undefined, args);
}
// User is pressing Backspace
else if (data.key == KEY_BACKSPACE) {
return onBackspace.apply(undefined, args);
}
}
/**
* User is pasting content, insert it as text
*/
function onPaste(event, data, change) {
var state = change.state;
var currentCode = getCurrentCode(opts, state);
// Only handle paste when selection is completely a code block
var endBlock = state.endBlock;
if (!currentCode || !currentCode.hasDescendant(endBlock.key)) {
return;
}
// Convert to text if needed
var text = void 0;
if (data.type === 'fragment') {
text = data.fragment.getTexts().map(function (t) {
return t.text;
}).join('\n');
} else {
text = data.text;
}
// Convert the text to code lines
var lines = deserializeCode(opts, text).nodes;
var fragment = Document.create({ nodes: lines });
return change.insertFragment(fragment);
}
var schema = makeSchema(opts);
return {
onKeyDown: _onKeyDown,
onPaste: onPaste,
schema: schema,
changes: {
unwrapCodeBlockByKey: unwrapCodeBlockByKey.bind(null, opts),
wrapCodeBlockByKey: wrapCodeBlockByKey.bind(null, opts),
wrapCodeBlock: wrapCodeBlock.bind(null, opts),
unwrapCodeBlock: unwrapCodeBlock.bind(null, opts),
toggleCodeBlock: toggleCodeBlock.bind(null, opts)
},
utils: {
isInCodeBlock: isInCodeBlock.bind(null, opts),
deserializeCode: deserializeCode.bind(null, opts)
}
};
}
module.exports = EditCode;
},{"./changes/toggleCodeBlock":5,"./changes/unwrapCodeBlock":6,"./changes/unwrapCodeBlockByKey":7,"./changes/wrapCodeBlock":8,"./changes/wrapCodeBlockByKey":9,"./deserializeCode":10,"./getCurrentCode":11,"./isInCodeBlock":15,"./makeSchema":16,"./onBackspace":17,"./onEnter":18,"./onModEnter":19,"./onSelectAll":20,"./onShiftTab":21,"./onTab":22,"./options":23,"slate":330}],15:[function(require,module,exports){
"use strict";
/**
* Test if current selection is in a code block.
* @param {State} state
* @return {Boolean}
*/
function isInCodeBlock(opts, state) {
var document = state.document,
startKey = state.startKey;
var codeBlock = document.getClosest(startKey, function (block) {
return block.type === opts.containerType;
});
return Boolean(codeBlock);
}
module.exports = isInCodeBlock;
},{}],16:[function(require,module,exports){
'use strict';
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _require = require('immutable'),
Set = _require.Set,
List = _require.List;
var Slate = require('slate');
/**
* Create a schema for code blocks.
* @param {Options} opts
* @return {Object} A schema definition with normalization rules
*/
function makeSchema(opts) {
return {
rules: [noOrphanLine(opts), onlyLine(opts), onlyText(opts), noMarks(opts)]
};
}
/**
* @return {Object} A rule that ensure code lines are always children
* of a code block.
*/
function noOrphanLine(opts) {
return {
// Match all blocks that are not code blocks
match: function match(node) {
return (node.kind === 'block' || node.kind === 'document') && node.type !== opts.containerType;
},
validate: function validate(node) {
var codeLines = node.nodes.filter(function (n) {
return n.type === opts.lineType;
});
if (codeLines.isEmpty()) {
// All good
return null;
} else {
// Wrap the orphan lines
return {
toWrap: codeLines
};
}
},
/**
* Wrap the given blocks in code containers
* @param {List<Nodes>} value.toWrap
*/
normalize: function normalize(change, node, value) {
return value.toWrap.reduce(function (c, n) {
return c.wrapBlockByKey(n.key, opts.containerType);
}, change);
}
};
}
/**
* @return {Object} A rule that ensure code blocks only contain lines of code, and no marks
*/
function onlyLine(opts) {
return {
match: function match(node) {
return node.type === opts.containerType;
},
validate: function validate(node) {
var nodes = node.nodes;
var toWrap = [];
var toRemove = [];
nodes.forEach(function (child) {
if (child.kind === 'text') toWrap.push(child);else if (child.type !== opts.lineType) toRemove.push(child);
});
if (toWrap.length || toRemove.length) {
return { toWrap: toWrap, toRemove: toRemove };
} else {
return null;
}
},
normalize: function normalize(change, node, _ref) {
var toWrap = _ref.toWrap,
toRemove = _ref.toRemove;
toRemove.forEach(function (child) {
change.removeNodeByKey(child.key);
});
toWrap.forEach(function (child) {
change.wrapBlockByKey(child.key, opts.lineType);
});
// Also remove marks here (since the no mark rule for
// lines will not be applied afterward).
return applyRule(noMarks(opts), change, node.key);
}
};
}
/**
* @return {Object} A rule that ensure code lines only contain one text
* node.
*/
function onlyText(opts) {
return {
match: function match(node) {
return node.type === opts.lineType;
},
validate: function validate(node) {
var nodes = node.nodes;
var toRemove = nodes.filterNot(function (n) {
return n.kind === 'text';
});
if (!toRemove.isEmpty()) {
// Remove them, and the rest
// will be done in the next validation call.
return { toRemove: toRemove };
}
// Else, there are only text nodes
else if (nodes.size > 1) {
return { toJoin: nodes };
} else if (nodes.size === 0) {
return { toAdd: [Slate.Text.create()] };
} else {
// There is a single text node -> valid
return null;
}
},
/**
* Clean up the child nodes.
*/
normalize: function normalize(change, node, _ref2) {
var _ref2$toRemove = _ref2.toRemove,
toRemove = _ref2$toRemove === undefined ? List() : _ref2$toRemove,
_ref2$toAdd = _ref2.toAdd,
toAdd = _ref2$toAdd === undefined ? List() : _ref2$toAdd,
_ref2$toJoin = _ref2.toJoin,
toJoin = _ref2$toJoin === undefined ? List() : _ref2$toJoin;
// Remove invalids
toRemove.reduce(function (c, child) {
return c.removeNodeByKey(child.key, { normalize: false });
}, change);
// Join nodes.
var pairs = toJoin.butLast().map(function (child, index) {
return [child.key, toJoin.get(index + 1).key];
});
// Join every node onto the previous one.
pairs.reverse().reduce(function (c, _ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
childKey = _ref4[0],
nextChildKey = _ref4[1];
return c.joinNodeByKey(nextChildKey, childKey, { normalize: false });
}, change);
// Add missing nodes
toAdd.reduce(function (c, child) {
return c.insertNodeByKey(node.key, 0, child);
}, change);
return change;
}
};
}
/**
* @return {Object} A rule that ensure code blocks contains no marks
*/
function noMarks(opts) {
return {
// Match at the line level, to optimize memoization
match: function match(node) {
return node.type === opts.lineType;
},
validate: function validate(node) {
if (opts.allowMarks) return null;
var marks = getMarks(node);
if (marks.isEmpty()) {
return null;
} else {
return {
removeMarks: marks
};
}
},
/**
* Removes the given marks
* @param {Set<Marks>} value.removeMarks
*/
normalize: function normalize(change, node, _ref5) {
var removeMarks = _ref5.removeMarks;
var selection = change.state.selection;
var range = selection.moveToRangeOf(node);
return removeMarks.reduce(function (c, mark) {
return c.removeMarkAtRange(range, mark);
}, change);
}
};
}
/**
* @param {Node} node
* @return {Set<Marks>} All the marks in the node
*/
function getMarks(node) {
var texts = node.getTexts();
var marks = texts.reduce(function (all, text) {
return text.characters.reduce(function (accu, chars) {
return accu.union(chars.marks);
}, all);
}, new Set());
return marks;
}
/**
* Apply a normalization rule to a node
* @param {Rule} rule
* @param {Change} change
* @param {String} key
* @return {Change}
*/
function applyRule(rule, change, key) {
var node = change.state.document.getDescendant(key);
var notValid = rule.validate(node);
if (notValid) {
rule.normalize(change, node, notValid);
}
return change;
}
module.exports = makeSchema;
},{"immutable":135,"slate":330}],17:[function(require,module,exports){
'use strict';
var endsWith = require('ends-with');
var getCurrentIndent = require('./getCurrentIndent');
var getCurrentCode = require('./getCurrentCode');
/**
* User pressed Delete in an editor:
* Remove last idnentation before cursor
*/
function onBackspace(event, data, change, opts) {
var state = change.state;
if (state.isExpanded) {
return;
}
var startOffset = state.startOffset,
startText = state.startText;
var currentLine = state.startBlock;
// Detect and remove indentation at cursor
var indent = getCurrentIndent(opts, state);
var beforeSelection = currentLine.text.slice(0, startOffset);
// If the line before selection ending with the indentation?
if (endsWith(beforeSelection, indent)) {
// Remove indent
event.preventDefault();
return change.deleteBackward(indent.length).focus();
}
// Otherwise check if we are in an empty code container...
else if (opts.exitBlockType) {
var currentCode = getCurrentCode(opts, state);
var isStartOfCode = startOffset === 0 && currentCode.getFirstText() === startText;
// PERF: avoid checking for whole currentCode.text
var isEmpty = currentCode.nodes.size === 1 && currentLine.text.length === 0;
if (isStartOfCode && isEmpty) {
event.preventDefault();
// Convert it to default exit type
return change.setBlock(opts.exitBlockType).unwrapNodeByKey(currentLine.key);
}
}
}
module.exports = onBackspace;
},{"./getCurrentCode":11,"./getCurrentIndent":12,"ends-with":27}],18:[function(require,module,exports){
'use strict';
var getIndent = require('./getIndent');
/**
* User pressed Enter in an editor:
* Insert a new code line and start it with the indentation from previous line
*/
function onEnter(event, data, change, opts) {
var state = change.state;
if (!state.isCollapsed) {
return;
}
event.preventDefault();
var startBlock = state.startBlock;
var currentLineText = startBlock.text;
var indent = getIndent(currentLineText, '');
return change.splitBlock().insertText(indent).focus();
}
module.exports = onEnter;
},{"./getIndent":13}],19:[function(require,module,exports){
"use strict";
/**
* User pressed Mod+Enter in an editor
* Exit the current code block
*/
function onModEnter(event, data, change, opts) {
var state = change.state;
if (!state.isCollapsed) {
return;
}
event.preventDefault();
// Exit the code block
return opts.onExit(change, opts);
}
module.exports = onModEnter;
},{}],20:[function(require,module,exports){
'use strict';
var getCurrentCode = require('./getCurrentCode');
/**
* User is Cmd+A to select all text
*/
function onSelectAll(event, data, change, opts) {
var state = change.state;
event.preventDefault();
var currentCode = getCurrentCode(opts, state);
return change.collapseToStartOf(currentCode.getFirstText()).extendToEndOf(currentCode.getLastText());
}
module.exports = onSelectAll;
},{"./getCurrentCode":11}],21:[function(require,module,exports){
'use strict';
var getCurrentIndent = require('./getCurrentIndent');
var dedentLines = require('./changes/dedentLines');
/**
* User pressed Shift+Tab in an editor:
* Reduce indentation in the selected lines.
*/
function onShiftTab(event, data, change, opts) {
var state = change.state;
event.preventDefault();
event.stopPropagation();
var indent = getCurrentIndent(opts, state);
// We dedent all selected lines
return dedentLines(opts, change, indent);
}
module.exports = onShiftTab;
},{"./changes/dedentLines":3,"./getCurrentIndent":12}],22:[function(require,module,exports){
'use strict';
var getCurrentIndent = require('./getCurrentIndent');
var indentLines = require('./changes/indentLines');
/**
* User pressed Tab in an editor:
* Insert a tab after detecting it from code block content.
*/
function onTab(event, data, change, opts) {
var state = change.state;
event.preventDefault();
event.stopPropagation();
var isCollapsed = state.isCollapsed;
var indent = getCurrentIndent(opts, state);
// Selection is collapsed, we just insert an indent at cursor
if (isCollapsed) {
return change.insertText(indent).focus();
}
// We indent all selected lines
return indentLines(opts, change, indent);
}
module.exports = onTab;
},{"./changes/indentLines":4,"./getCurrentIndent":12}],23:[function(require,module,exports){
'use strict';
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _require = require('immutable'),
Record = _require.Record;
var DEFAULTS = {
// Type of the code containers
containerType: 'code_block',
// Type of the code lines
lineType: 'code_line',
// Mod+Enter will exit the code container, into the given block type.
// Backspace at start of empty code container, will turn it into the given block type.
exitBlockType: 'paragraph',
// Should the plugin handle the select all inside a code container
selectAll: true,
// Allow marks inside code blocks
allowMarks: false,
// Custom exit handler
// exitBlockType option is useless if onExit is provided
onExit: function onExit(change, options) {
// Exit the code block
change.insertBlock({ type: options.exitBlockType });
var inserted = change.state.startBlock;
return change.unwrapNodeByKey(inserted.key);
}
};
/**
* The plugin options
*/
var Options = function (_ref) {
_inherits(Options, _ref);
function Options() {
_classCallCheck(this, Options);
return _possibleConstructorReturn(this, (Options.__proto__ || Object.getPrototypeOf(Options)).apply(this, arguments));
}
return Options;
}(new Record(DEFAULTS));
module.exports = Options;
},{"immutable":135}],24:[function(require,module,exports){
/* eslint-disable guard-for-in */
'use strict';
var repeating = require('repeating');
// detect either spaces or tabs but not both to properly handle tabs
// for indentation and spaces for alignment
var INDENT_RE = /^(?:( )+|\t+)/;
function getMostUsed(indents) {
var result = 0;
var maxUsed = 0;
var maxWeight = 0;
for (var n in indents) {
var indent = indents[n];
var u = indent[0];
var w = indent[1];
if (u > maxUsed || u === maxUsed && w > maxWeight) {
maxUsed = u;
maxWeight = w;
result = Number(n);
}
}
return result;
}
module.exports = function (str) {
if (typeof str !== 'string') {
throw new TypeError('Expected a string');
}
// used to see if tabs or spaces are the most used
var tabs = 0;
var spaces = 0;
// remember the size of previous line's indentation
var prev = 0;
// remember how many indents/unindents as occurred for a given size
// and how much lines follow a given indentation
//
// indents = {
// 3: [1, 0],
// 4: [1, 5],
// 5: [1, 0],
// 12: [1, 0],
// }
var indents = {};
// pointer to the array of last used indent
var current;
// whether the last action was an indent (opposed to an unindent)
var isIndent;
str.split(/\n/g).forEach(function (line) {
if (!line) {
// ignore empty lines
return;
}
var indent;
var matches = line.match(INDENT_RE);
if (!matches) {
indent = 0;
} else {
indent = matches[0].length;
if (matches[1]) {
spaces++;
} else {
tabs++;
}
}
var diff = indent - prev;
prev = indent;
if (diff) {
// an indent or unindent has been detected
isIndent = diff > 0;
current = indents[isIndent ? diff : -diff];
if (current) {
current[0]++;
} else {
current = indents[diff] = [1, 0];
}
} else if (current) {
// if the last action was an indent, increment the weight
current[1] += Number(isIndent);
}
});
var amount = getMostUsed(indents);
var type;
var actual;
if (!amount) {
type = null;
actual = '';
} else if (spaces >= tabs) {
type = 'space';
actual = repeating(' ', amount);
} else {
type = 'tab';
actual = repeating('\t', amount);
}
return {
amount: amount,
type: type,
indent: actual
};
};
},{"repeating":310}],25:[function(require,module,exports){
'use strict';
module.exports = function (str) {
if (typeof str !== 'string') {
throw new TypeError('Expected a string');
}
var newlines = (str.match(/(?:\r?\n)/g) || []);
if (newlines.length === 0) {
return null;
}
var crlf = newlines.filter(function (el) {
return el === '\r\n';
}).length;
var lf = newlines.length - crlf;
return crlf > lf ? '\r\n' : '\n';
};
module.exports.graceful = function (str) {
return module.exports(str) || '\n';
};
},{}],26:[function(require,module,exports){
'use strict';
var GROUP_LEFT_TO_RIGHT,
GROUP_RIGHT_TO_LEFT,
EXPRESSION_LEFT_TO_RIGHT,
EXPRESSION_RIGHT_TO_LEFT;
/*
* Character ranges of left-to-right characters.
*/
GROUP_LEFT_TO_RIGHT = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' +
'\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' +
'\uFE00-\uFE6F\uFEFD-\uFFFF';
/*
* Character ranges of right-to-left characters.
*/
GROUP_RIGHT_TO_LEFT = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
/*
* Expression to match a left-to-right string.
*
* Matches the start of a string, followed by zero or
* more non-right-to-left characters, followed by a
* left-to-right character.
*/
EXPRESSION_LEFT_TO_RIGHT = new RegExp(
'^[^' + GROUP_RIGHT_TO_LEFT + ']*[' + GROUP_LEFT_TO_RIGHT + ']'
);
/*
* Expression to match a right-to-left string.
*
* Matches the start of a string, followed by zero or
* more non-left-to-right characters, followed by a
* right-to-left character.
*/
EXPRESSION_RIGHT_TO_LEFT = new RegExp(
'^[^' + GROUP_LEFT_TO_RIGHT + ']*[' + GROUP_RIGHT_TO_LEFT + ']'
);
/**
* Detect the direction of text.
*
* @param {string} value - value to stringify and check.
* @return {string} - One of `"rtl"`, `"ltr"`, or
* `"neutral"`.
*/
function direction(value) {
value = value.toString();
if (EXPRESSION_RIGHT_TO_LEFT.test(value)) {
return 'rtl';
}
if (EXPRESSION_LEFT_TO_RIGHT.test(value)) {
return 'ltr';
}
return 'neutral';
}
/*
* Expose `direction`.
*/
module.exports = direction;
},{}],27:[function(require,module,exports){
/*!
* ends-with <https://github.com/jonschlinkert/ends-with>
*
* Copyright (c) 2014 Jon Schlinkert, contributors.
* Licensed under the MIT license.
*/
'use strict';
module.exports = function (a, b) {
if (Array.isArray(a)) {
return a[a.length - 1] === b;
}
a = String(a);
b = String(b);
var i = b.length;
var len = a.length - i;
while (i--) {
if (b.charAt(i) !== a.charAt(len + i)) {
return false;
}
}
return true;
};
},{}],28:[function(require,module,exports){
'use strict';
module.exports = require('./is-implemented')() ? Map : require('./polyfill');
},{"./is-implemented":29,"./polyfill":107}],29:[function(require,module,exports){
'use strict';
module.exports = function () {
var map, iterator, result;
if (typeof Map !== 'function') return false;
try {
// WebKit doesn't support arguments and crashes
map = new Map([['raz', 'one'], ['dwa', 'two'], ['trzy', 'three']]);
} catch (e) {
return false;
}
if (String(map) !== '[object Map]') return false;
if (map.size !== 3) return false;
if (typeof map.clear !== 'function') return false;
if (typeof map.delete !== 'function') return false;
if (typeof map.entries !== 'function') return false;
if (typeof map.forEach !== 'function') return false;
if (typeof map.get !== 'function') return false;
if (typeof map.has !== 'function') return false;
if (typeof map.keys !== 'function') return false;
if (typeof map.set !== 'function') return false;
if (typeof map.values !== 'function') return false;
iterator = map.entries();
result = iterator.next();
if (result.done !== false) return false;
if (!result.value) return false;
if (result.value[0] !== 'raz') return false;
if (result.value[1] !== 'one') return false;
return true;
};
},{}],30:[function(require,module,exports){
// Exports true if environment provides native `Map` implementation,
// whatever that is.
'use strict';
module.exports = (function () {
if (typeof Map === 'undefined') return false;
return (Object.prototype.toString.call(new Map()) === '[object Map]');
}());
},{}],31:[function(require,module,exports){
'use strict';
module.exports = require('es5-ext/object/primitive-set')('key',
'value', 'key+value');
},{"es5-ext/object/primitive-set":84}],32:[function(require,module,exports){
'use strict';
var setPrototypeOf = require('es5-ext/object/set-prototype-of')
, d = require('d')
, Iterator = require('es6-iterator')
, toStringTagSymbol = require('es6-symbol').toStringTag
, kinds = require('./iterator-kinds')
, defineProperties = Object.defineProperties
, unBind = Iterator.prototype._unBind
, MapIterator;
MapIterator = module.exports = function (map, kind) {
if (!(this instanceof MapIterator)) return new MapIterator(map, kind);
Iterator.call(this, map.__mapKeysData__, map);
if (!kind || !kinds[kind]) kind = 'key+value';
defineProperties(this, {
__kind__: d('', kind),
__values__: d('w', map.__mapValuesData__)
});
};
if (setPrototypeOf) setPrototypeOf(MapIterator, Iterator);
MapIterator.prototype = Object.create(Iterator.prototype, {
constructor: d(MapIterator),
_resolve: d(function (i) {
if (this.__kind__ === 'value') return this.__values__[i];
if (this.__kind__ === 'key') return this.__list__[i];
return [this.__list__[i], this.__values__[i]];
}),
_unBind: d(function () {
this.__values__ = null;
unBind.call(this);
}),
toString: d(function () { return '[object Map Iterator]'; })
});
Object.defineProperty(MapIterator.prototype, toStringTagSymbol,
d('c', 'Map Iterator'));
},{"./iterator-kinds":31,"d":34,"es5-ext/object/set-prototype-of":85,"es6-iterator":97,"es6-symbol":101}],33:[function(require,module,exports){
'use strict';
var copy = require('es5-ext/object/copy')
, normalizeOptions = require('es5-ext/object/normalize-options')
, ensureCallable = require('es5-ext/object/valid-callable')
, map = require('es5-ext/object/map')
, callable = require('es5-ext/object/valid-callable')
, validValue = require('es5-ext/object/valid-value')
, bind = Function.prototype.bind, defineProperty = Object.defineProperty
, hasOwnProperty = Object.prototype.hasOwnProperty
, define;
define = function (name, desc, options) {
var value = validValue(desc) && callable(desc.value), dgs;
dgs = copy(desc);
delete dgs.writable;
delete dgs.value;
dgs.get = function () {
if (!options.overwriteDefinition && hasOwnProperty.call(this, name)) return value;
desc.value = bind.call(value, options.resolveContext ? options.resolveContext(this) : this);
defineProperty(this, name, desc);
return this[name];
};
return dgs;
};
module.exports = function (props/*, options*/) {
var options = normalizeOptions(arguments[1]);
if (options.resolveContext != null) ensureCallable(options.resolveContext);
return map(props, function (desc, name) { return define(name, desc, options); });
};
},{"es5-ext/object/copy":73,"es5-ext/object/map":82,"es5-ext/object/normalize-options":83,"es5-ext/object/valid-callable":88,"es5-ext/object/valid-value":89}],34:[function(require,module,exports){
'use strict';
var assign = require('es5-ext/object/assign')
, normalizeOpts = require('es5-ext/object/normalize-options')
, isCallable = require('es5-ext/object/is-callable')
, contains = require('es5-ext/string/#/contains')
, d;
d = module.exports = function (dscr, value/*, options*/) {
var c, e, w, options, desc;
if ((arguments.length < 2) || (typeof dscr !== 'string')) {
options = value;
value = dscr;
dscr = null;
} else {
options = arguments[2];
}
if (dscr == null) {
c = w = true;
e = false;
} else {
c = contains.call(dscr, 'c');
e = contains.call(dscr, 'e');
w = contains.call(dscr, 'w');
}
desc = { value: value, configurable: c, enumerable: e, writable: w };
return !options ? desc : assign(normalizeOpts(options), desc);
};
d.gs = function (dscr, get, set/*, options*/) {
var c, e, options, desc;
if (typeof dscr !== 'string') {
options = set;
set = get;
get = dscr;
dscr = null;
} else {
options = arguments[3];
}
if (get == null) {
get = undefined;
} else if (!isCallable(get)) {
options = get;
get = set = undefined;
} else if (set == null) {
set = undefined;
} else if (!isCallable(set)) {
options = set;
set = undefined;
}
if (dscr == null) {
c = true;
e = false;
} else {
c = contains.call(dscr, 'c');
e = contains.call(dscr, 'e');
}
desc = { get: get, set: set, configurable: c, enumerable: e };
return !options ? desc : assign(normalizeOpts(options), desc);
};
},{"es5-ext/object/assign":70,"es5-ext/object/is-callable":76,"es5-ext/object/normalize-options":83,"es5-ext/string/#/contains":90}],35:[function(require,module,exports){
// Inspired by Google Closure:
// http://closure-library.googlecode.com/svn/docs/
// closure_goog_array_array.js.html#goog.array.clear
"use strict";
var value = require("../../object/valid-value");
module.exports = function () {
value(this).length = 0;
return this;
};
},{"../../object/valid-value":89}],36:[function(require,module,exports){
"use strict";
var numberIsNaN = require("../../number/is-nan")
, toPosInt = require("../../number/to-pos-integer")
, value = require("../../object/valid-value")
, indexOf = Array.prototype.indexOf
, objHasOwnProperty = Object.prototype.hasOwnProperty
, abs = Math.abs
, floor = Math.floor;
module.exports = function (searchElement /*, fromIndex*/) {
var i, length, fromIndex, val;
if (!numberIsNaN(searchElement)) return indexOf.apply(this, arguments);
length = toPosInt(value(this).length);
fromIndex = arguments[1];
if (isNaN(fromIndex)) fromIndex = 0;
else if (fromIndex >= 0) fromIndex = floor(fromIndex);
else fromIndex = toPosInt(this.length) - floor(abs(fromIndex));
for (i = fromIndex; i < length; ++i) {
if (objHasOwnProperty.call(this, i)) {
val = this[i];
if (numberIsNaN(val)) return i; // Jslint: ignore
}
}
return -1;
};
},{"../../number/is-nan":64,"../../number/to-pos-integer":68,"../../object/valid-value":89}],37:[function(require,module,exports){
"use strict";
module.exports = require("./is-implemented")()
? Array.from
: require("./shim");
},{"./is-implemented":38,"./shim":39}],38:[function(require,module,exports){
"use strict";
module.exports = function () {
var from = Array.from, arr, result;
if (typeof from !== "function") return false;
arr = ["raz", "dwa"];
result = from(arr);
return Boolean(result && (result !== arr) && (result[1] === "dwa"));
};
},{}],39:[function(require,module,exports){
"use strict";
var iteratorSymbol = require("es6-symbol").iterator
, isArguments = require("../../function/is-arguments")
, isFunction = require("../../function/is-function")
, toPosInt = require("../../number/to-pos-integer")
, callable = require("../../object/valid-callable")
, validValue = require("../../object/valid-value")
, isValue = require("../../object/is-value")
, isString = require("../../string/is-string")
, isArray = Array.isArray
, call = Function.prototype.call
, desc = { configurable: true, enumerable: true, writable: true, value: null }
, defineProperty = Object.defineProperty;
// eslint-disable-next-line complexity
module.exports = function (arrayLike /*, mapFn, thisArg*/) {
var mapFn = arguments[1]
, thisArg = arguments[2]
, Context
, i
, j
, arr
, length
, code
, iterator
, result
, getIterator
, value;
arrayLike = Object(validValue(arrayLike));
if (isValue(mapFn)) callable(mapFn);
if (!this || this === Array || !isFunction(this)) {
// Result: Plain array
if (!mapFn) {
if (isArguments(arrayLike)) {
// Source: Arguments
length = arrayLike.length;
if (length !== 1) return Array.apply(null, arrayLike);
arr = new Array(1);
arr[0] = arrayLike[0];
return arr;
}
if (isArray(arrayLike)) {
// Source: Array
arr = new Array(length = arrayLike.length);
for (i = 0; i < length; ++i) arr[i] = arrayLike[i];
return arr;
}
}
arr = [];
} else {
// Result: Non plain array
Context = this;
}
if (!isArray(arrayLike)) {
if ((getIterator = arrayLike[iteratorSymbol]) !== undefined) {
// Source: Iterator
iterator = callable(getIterator).call(arrayLike);
if (Context) arr = new Context();
result = iterator.next();
i = 0;
while (!result.done) {
value = mapFn ? call.call(mapFn, thisArg, result.value, i) : result.value;
if (Context) {
desc.value = value;
defineProperty(arr, i, desc);
} else {
arr[i] = value;
}
result = iterator.next();
++i;