draftmirror
Advanced tools
Comparing version 0.2.5 to 0.3.0
@@ -11,3 +11,3 @@ module.exports = { | ||
'type': 'text', | ||
'text': 'Hello World!' | ||
'text': 'Hello #World!' | ||
} | ||
@@ -14,0 +14,0 @@ ] |
@@ -26,2 +26,3 @@ var React = require('react'); | ||
var testDecorator = DraftMirror.createDecorator(function(contentBlock, callback) { | ||
console.log('find hashtag in ', JSON.stringify(contentBlock.text)); | ||
findWithRegex(HASHTAG_REGEX, contentBlock, 'decorate-hashtag', callback); | ||
@@ -28,0 +29,0 @@ }); |
@@ -14,2 +14,3 @@ /** | ||
// hack using private apis! | ||
var toRemove = []; | ||
editor.ranges.ranges.forEach(function(range) { | ||
@@ -22,5 +23,10 @@ if (range.options.decorator !== decorator.id) { | ||
|| (range.to >= blockOffset && range.to <= blockEndOffset)) { | ||
editor.removeRange(range); | ||
toRemove.push(range); | ||
} | ||
}); | ||
for (var i = 0; i < toRemove.length; i++) { | ||
editor.removeRange(toRemove[i]); | ||
} | ||
editor.ranges.sorted.resort(); | ||
@@ -27,0 +33,0 @@ |
@@ -8,2 +8,3 @@ var React = require('react'); | ||
var applyDecoratorsToDoc = require('./decorators/applyDecoratorsToDoc'); | ||
var compareNodes = require('./decorators/compareNodes'); | ||
@@ -33,2 +34,3 @@ var TooltipUtils = require('./tooltips'); | ||
onChanged: function() { | ||
var that = this; | ||
var editorState = this.props.editorState; | ||
@@ -41,2 +43,3 @@ var newEditorState = editorState; | ||
selection: this.editor.selection, | ||
activeMarks: this.editor.activeMarks(), | ||
transforms: Immutable.List() | ||
@@ -46,5 +49,6 @@ }) | ||
// TODO: Optimization | ||
// Use applyDecorators on block that changed | ||
applyDecoratorsToDoc(this.props.decorators, this.editor); | ||
compareNodes(editorState.getDoc(), newEditorState.getDoc(), function(node, offset) { | ||
applyDecorators(that.props.decorators, that.editor, node, offset); | ||
}); | ||
@@ -64,15 +68,2 @@ if (!Immutable.is(editorState, newEditorState)) { | ||
/** | ||
* Filter transformation when readonly | ||
*/ | ||
onClickOn: function(pos, node) { | ||
if (!this.props.onClickOn) { | ||
return; | ||
} | ||
return this.props.onClickOn({ | ||
type: node.type.name | ||
}); | ||
}, | ||
/** | ||
* Update keymaps | ||
@@ -96,6 +87,3 @@ * todo: update on componentWillReceiveProps | ||
if (this.editor) { | ||
this.editor.on.change.remove(this.onChanged); | ||
this.editor.on.selectionChange.remove(this.onChanged); | ||
this.editor.on.filterTransform.remove(this.onFilterTransform); | ||
this.editor.on.clickOn.remove(this.onClickOn); | ||
this.bindListeners(this.editor, 'remove'); | ||
div.innerHTML = ''; | ||
@@ -110,7 +98,6 @@ } | ||
this.editor.on.change.add(this.onChanged); | ||
this.editor.on.selectionChange.add(this.onChanged); | ||
this.editor.on.filterTransform.add(this.onFilterTransform); | ||
this.editor.on.clickOn.add(this.onClickOn); | ||
this.bindListeners(this.editor, 'add'); | ||
applyDecoratorsToDoc(this.props.decorators, this.editor); | ||
this.updateKeymaps(); | ||
@@ -120,2 +107,11 @@ }, | ||
/** | ||
* @param {ProseMirror.Editor} editor | ||
* @param {String} action 'add' | 'remove' | ||
*/ | ||
bindListeners: function (editor, action) { | ||
this.editor.on.filterTransform[action](this.onFilterTransform); | ||
this.editor.on.flush[action](this.onChanged); | ||
}, | ||
/** | ||
* Mount the prosemirror editor | ||
@@ -177,23 +173,33 @@ */ | ||
renderTooltip: function() { | ||
var editorState = this.props.editorState; | ||
var selection = editorState.getSelection(); | ||
// Rendering tooltips still has quite a few issues, so guard against errors | ||
// This avoid corrupting the Editor update loop if it fails | ||
try { | ||
var editorState = this.props.editorState; | ||
var selection = editorState.getSelection(); | ||
if (!selection || !this.editor || !this.editor.hasFocus()) { | ||
return undefined; | ||
} | ||
if (!selection || !this.editor || !this.editor.hasFocus()) { | ||
return undefined; | ||
} | ||
var context = SelectionUtils.contextAtSelection(editorState, selection); | ||
var tooltip = this.props.getTooltip(context); | ||
var context = SelectionUtils.contextAtSelection(editorState, selection); | ||
var tooltip = this.props.getTooltip(context); | ||
if (!tooltip) { | ||
return undefined; | ||
} | ||
if (!tooltip) { | ||
return undefined; | ||
} | ||
var inner = React.createElement(tooltip.component, tooltip.props); | ||
var inner = React.createElement(tooltip.component, tooltip.props); | ||
return React.createElement('div', { | ||
className: 'DraftMirrorEditor-Tooltip', | ||
style: tooltipStyle(this.editor, selection, tooltip) | ||
}, inner); | ||
return React.createElement('div', { | ||
className: 'DraftMirrorEditor-Tooltip', | ||
style: tooltipStyle(this.editor, selection, tooltip) | ||
}, inner); | ||
} catch (e) { | ||
// Unable to render tooltip | ||
// Eventually throw the error | ||
setTimeout(function () { throw e; }); | ||
return undefined; | ||
} | ||
}, | ||
@@ -200,0 +206,0 @@ |
@@ -15,2 +15,5 @@ var Immutable = require('immutable'); | ||
// Active marks (but not marks at current position) | ||
activeMarks: Immutable.List(), | ||
// Current history of editor (editor.history) | ||
@@ -38,2 +41,6 @@ history: null, | ||
EditorState.prototype.getActiveMarks = function() { | ||
return this.get('activeMarks'); | ||
}; | ||
EditorState.prototype.getHistory = function() { | ||
@@ -145,2 +152,11 @@ return this.get('history'); | ||
/** | ||
* Focus the editor (does not actually change the state) | ||
*/ | ||
EditorState.prototype.focus = function() { | ||
return this.applyTransform(function (pm) { | ||
pm.focus(); | ||
}); | ||
}; | ||
/** | ||
* Create an editor state | ||
@@ -176,2 +192,22 @@ * @param {Object} props | ||
/** | ||
* @param {?EditorState} previousState | ||
* @param {?EditorState} newState | ||
* @param {Boolean} [ignoreTransforms=true] | ||
* @return {Boolean} True if actual content changed | ||
*/ | ||
EditorState.contentChanged = function(previousState, newState, ignoreTransforms) { | ||
ignoreTransforms = ignoreTransforms === undefined ? true : ignoreTransforms; | ||
if (previousState === newState) { | ||
return false; | ||
} else if (!previousState || !newState) { | ||
return true; | ||
} else { | ||
var differentTransforms = previousState.getTransforms() !== newState.getTransforms(); | ||
var differentDoc = previousState.getDoc() !== newState.getDoc(); | ||
return (differentDoc | ||
|| (!ignoreTransforms && differentTransforms)); | ||
} | ||
}; | ||
module.exports = EditorState; |
@@ -25,3 +25,3 @@ var StyleUtils = require('./style'); | ||
* @param {Object} attrs | ||
* @param {String} [type] To use the closest parent Node with given type as target | ||
* @param {String} [type] To edit the closest parent entity with given type | ||
* @return {EditorState} | ||
@@ -48,6 +48,10 @@ */ | ||
var doc = editorState.getDoc(); | ||
var node = editorState.getDoc().nodeAt(position); | ||
var node = doc.nodeAt(position); | ||
if (node === null) { // happens if we are at the last token of a node | ||
node = doc.nodeAt(position - 1); | ||
} | ||
if (node.type === nodeType) { | ||
return position; | ||
} else { | ||
// Search the parent instead | ||
var resolved = doc.resolve(position); | ||
@@ -60,2 +64,23 @@ var parentPosition = resolved.pos - resolved.parentOffset - 1; | ||
/** | ||
* Remove the whole entity at point. | ||
* @param {EditorState} editorState | ||
* @param {String} [type] To remove the closest parent entity with given type | ||
*/ | ||
function removeEntity(editorState, type) { | ||
var position = editorState.getSelection().head; | ||
if (type) { | ||
position = _positionForParentType(editorState, editorState.getNodeType(type), position); | ||
} | ||
var doc = editorState.getDoc(); | ||
var node = doc.nodeAt(position); | ||
var start = position; | ||
var end = start + node.nodeSize; | ||
return editorState.applyTransform(function(editor) { | ||
editor.tr.delete(start, end).apply(); | ||
}); | ||
} | ||
/** | ||
* Change type fo current node or insert an entity in the middle | ||
@@ -84,3 +109,4 @@ * | ||
editEntity: editEntity, | ||
removeEntity: removeEntity, | ||
toggleBlockOrInline: toggleBlockOrInline | ||
}; |
@@ -10,3 +10,3 @@ var NodeRange = require('prosemirror/dist/model').NodeRange; | ||
/** | ||
* Toggle an inline style. | ||
* Toggle an inline style on cursor or selection. | ||
* | ||
@@ -20,3 +20,2 @@ * @param {EditorState} editorState | ||
var mark = editorState.getMarkType(type); | ||
return editorState.applyTransform(commands.toggleMark(mark, attrs)); | ||
@@ -208,19 +207,21 @@ } | ||
* @param {EditorState} editorState | ||
* @param {Sting} type | ||
* @param {String} type | ||
* @return {Boolean} | ||
*/ | ||
function hasInlineStyle(editorState, type) { | ||
var mark = editorState.getMarkType(type); | ||
var selection = editorState.getSelection(); | ||
var schema = editorState.getSchema(); | ||
var doc = editorState.getDoc(); | ||
if (!selection) { | ||
return false; | ||
} else if (selection.empty) { | ||
var activeMarks = editorState.getActiveMarks().toArray(); | ||
return Boolean(mark.isInSet(activeMarks)); | ||
} else { | ||
var from = selection.from; | ||
var to = selection.to; | ||
var doc = editorState.getDoc(); | ||
return doc.rangeHasMark(from, to, mark); | ||
} | ||
var mark = schema.marks[type]; | ||
var from = selection.from; | ||
var to = selection.to; | ||
return doc.rangeHasMark(from, to, mark); | ||
} | ||
@@ -302,16 +303,53 @@ | ||
/** | ||
* @param {EditorState} editorState | ||
* @param {Array<MarkRangeParam> marks List of params to pass on | ||
* marking ranges as object of the form { from, to, options } | ||
* http://prosemirror.net/ref.html#ProseMirror.markRange | ||
* @param {Function} receiveMarkedRanges callback called with the created ProseMirror.MarkRanges | ||
* @return {EditorState} | ||
*/ | ||
function markRanges(editorState, marks, receiveMarkedRanges) { | ||
return editorState.applyTransform(function (pm) { | ||
var markedRanges = []; | ||
marks.forEach(function (mark) { | ||
markedRanges.push(pm.markRange(mark.from, mark.to, mark.options)); | ||
}); | ||
receiveMarkedRanges(markedRanges); | ||
}); | ||
} | ||
/** | ||
* @param {EditorState} editorState | ||
* @param {Array<MarkRange>} markedRanges to remove | ||
* @return {EditorState} | ||
*/ | ||
function removeMarkedRanges(editorState, markedRanges) { | ||
if (markedRanges.length === 0) { | ||
return editorState; | ||
} | ||
return editorState.applyTransform(function (pm) { | ||
markedRanges.forEach(function (markedRange) { | ||
pm.removeRange(markedRange); | ||
}); | ||
}); | ||
} | ||
module.exports = { | ||
toggleInlineStyle: toggleInlineStyle, | ||
toggleBlockType: toggleBlockType, | ||
toggleBlockOrInline: toggleBlockOrInline, | ||
wrapBlock: wrapBlock, | ||
wrapInList: wrapInList, | ||
canWrap: canWrap, | ||
canWrapInList: canWrapInList, | ||
unwrapBlock: unwrapBlock, | ||
canUnwrap: canUnwrap, | ||
hasBlockType: hasBlockType, | ||
hasInlineStyle: hasInlineStyle, | ||
replaceInlineStyle: replaceInlineStyle, | ||
removeInlineStyle: removeInlineStyle | ||
toggleInlineStyle: toggleInlineStyle, | ||
toggleBlockType: toggleBlockType, | ||
toggleBlockOrInline: toggleBlockOrInline, | ||
wrapBlock: wrapBlock, | ||
wrapInList: wrapInList, | ||
canWrap: canWrap, | ||
canWrapInList: canWrapInList, | ||
unwrapBlock: unwrapBlock, | ||
canUnwrap: canUnwrap, | ||
hasBlockType: hasBlockType, | ||
hasInlineStyle: hasInlineStyle, | ||
markRanges: markRanges, | ||
removeMarkedRanges: removeMarkedRanges, | ||
replaceInlineStyle: replaceInlineStyle, | ||
removeInlineStyle: removeInlineStyle | ||
}; |
var tableCommands = require('prosemirror/dist/commands-table'); | ||
var schemaTable = require('prosemirror/dist/schema-table'); | ||
var Keymap = require('../models/keymap'); | ||
var EntityUtils = require('./entity'); | ||
@@ -29,2 +30,14 @@ /** | ||
/** | ||
* Removes the whole table at point | ||
* | ||
* @param {EditorState} editorState | ||
* @param {String} tableType the type of the table to remove | ||
* @return {EditorState} | ||
*/ | ||
function removeTable(editorState, tableType) { | ||
tableType = tableType || 'table'; | ||
return EntityUtils.removeEntity(editorState, tableType); | ||
} | ||
/** | ||
* Test if a transform can be applied | ||
@@ -224,2 +237,3 @@ */ | ||
createTable: createTable, | ||
removeTable: removeTable, | ||
canInsertTable: canInsertTable, | ||
@@ -226,0 +240,0 @@ canEditTable: canEditTable, |
@@ -56,13 +56,2 @@ /** | ||
* @param {Selection} selection | ||
* @param {String} markType | ||
* @return {{left, right, top, bottom}} Bounding box of the mark at selection | ||
*/ | ||
function markAtSelectionBoundingBox(editor, selection, markType) { | ||
// TODO | ||
return selectionBoundingBox(editor, selection); | ||
} | ||
/** | ||
* @param {Editor} editor | ||
* @param {Selection} selection | ||
* @return {{left, right, top, bottom}} Bounding box of the | ||
@@ -73,3 +62,13 @@ * selection. | ||
var before = editor.coordsAtPos(selection.$from.pos); | ||
var after = editor.coordsAtPos(selection.$to.pos); | ||
var after; | ||
// Can fail if there is no more node at $to | ||
try { | ||
after = editor.coordsAtPos(selection.$to.pos); | ||
} catch (e) { | ||
if (e.name === 'RangeError') { | ||
after = before; | ||
} else { | ||
throw e; | ||
} | ||
} | ||
@@ -133,4 +132,3 @@ var result = { | ||
selectionBoundingBox: selectionBoundingBox, | ||
nodeAtSelectionBoundingBox: nodeAtSelectionBoundingBox, | ||
markAtSelectionBoundingBox: markAtSelectionBoundingBox | ||
nodeAtSelectionBoundingBox: nodeAtSelectionBoundingBox | ||
}; |
@@ -51,4 +51,6 @@ var React = require('react'); | ||
} else { | ||
var isInline = spec.isInline(node); | ||
node.rendered = dom.elt('figure', { | ||
class: 'DraftMirror-Widget Widget-' + this.name + ' ' + (spec.isInline()? 'inline' : 'block') | ||
class: 'DraftMirror-Widget Widget-' + this.name + ' ' + (isInline? 'inline' : 'block') | ||
}, ''); | ||
@@ -58,3 +60,3 @@ | ||
attrs: node.attrs, | ||
inline: spec.isInline() | ||
inline: isInline | ||
}); | ||
@@ -61,0 +63,0 @@ |
@@ -0,1 +1,2 @@ | ||
var is = require('is'); | ||
var Immutable = require('immutable'); | ||
@@ -5,2 +6,3 @@ | ||
// Inline or block widget | ||
// This can be a funciton | ||
inline: true, | ||
@@ -18,4 +20,11 @@ | ||
WidgetSpec.prototype.isInline = function() { | ||
return this.get('inline'); | ||
/** | ||
* Test if a node should be rendered as inline or not | ||
* @param {Node} node | ||
* @return {Boolean} | ||
*/ | ||
WidgetSpec.prototype.isInline = function(node) { | ||
var isInline = this.get('inline'); | ||
return is.fn(isInline)? isInline(node) : isInline; | ||
}; | ||
@@ -22,0 +31,0 @@ |
{ | ||
"name": "draftmirror", | ||
"version": "0.2.5", | ||
"version": "0.3.0", | ||
"description": "React component for ProseMirror providing a Draft.js like API", | ||
@@ -30,2 +30,3 @@ "main": "./lib/index.js", | ||
"immutable": "^3.8.1", | ||
"is": "^3.1.0", | ||
"prosemirror": "^0.8.1", | ||
@@ -32,0 +33,0 @@ "react": "^15.1.0", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
76761
31
1959
5