Skip to content

Commit

Permalink
implement native embed
Browse files Browse the repository at this point in the history
  • Loading branch information
jhchen committed Apr 16, 2015
1 parent e7933b8 commit 3b3bead
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 29 deletions.
2 changes: 1 addition & 1 deletion config/grunt/dist.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ module.exports = (grunt) ->
modifier: 'modern'
include: [
'difference', 'intersection', 'last'
'all', 'each', 'invoke', 'map', 'reduce'
'all', 'each', 'find', 'invoke', 'map', 'reduce'
'bind', 'defer', 'partial'
'clone', 'extend', 'defaults', 'omit', 'values'
'isElement', 'isEqual', 'isFunction', 'isNumber', 'isObject', 'isString'
Expand Down
9 changes: 7 additions & 2 deletions src/core/editor.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ class Editor
this._insertAt(index, op.insert, op.attributes)
index += op.insert.length;
else if _.isNumber(op.insert)
# TODO embed needs native insert
this._insertAt(index, dom.EMBED_TEXT, op.attributes)
this._insertEmbed(index, op.attributes)
index += 1;
else if _.isNumber(op.delete)
this._deleteAt(index, op.delete)
Expand Down Expand Up @@ -137,6 +136,12 @@ class Editor
line = line.next
)

_insertEmbed: (index, attributes) ->
@selection.shiftAfter(index, 1, =>
[line, offset] = @doc.findLineAt(index)
line.insertEmbed(offset, attributes)
)

_insertAt: (index, text, formatting = {}) ->
@selection.shiftAfter(index, text.length, =>
text = text.replace(/\r\n?/g, '\n')
Expand Down
6 changes: 5 additions & 1 deletion src/core/format.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ dom = require('../lib/dom')
class Format
@types:
LINE: 'line'
EMBED: 'embed'

@FORMATS:
bold:
Expand Down Expand Up @@ -56,6 +57,7 @@ class Format
return node.getAttribute('href')

image:
type: Format.types.EMBED
tag: 'IMG'
attribute: 'src'

Expand Down Expand Up @@ -157,9 +159,11 @@ class Format
dom(node).splitBefore(node.parentNode.parentNode) if node.previousSibling?
dom(node.nextSibling).splitBefore(node.parentNode.parentNode) if node.nextSibling?
node = dom(node).switchTag(dom.DEFAULT_BLOCK_TAG)
else if this.isType(Format.types.EMBED)
dom(node).remove()
return undefined
else
node = dom(node).switchTag(dom.DEFAULT_INLINE_TAG)
dom(node).text(dom.EMBED_TEXT) if dom.EMBED_TAGS[@config.tag]? # TODO is this desireable?
if _.isString(@config.parentTag)
dom(node.parentNode).unwrap()
if _.isFunction(@config.remove)
Expand Down
36 changes: 25 additions & 11 deletions src/core/line.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,37 @@ class Line extends LinkedList.Node
leaf = nextLeaf
this.rebuild()

_insert: (offset, node, formats) ->
[leaf, leafOffset] = this.findLeafAt(offset)
node = _.reduce(formats, (node, value, name) =>
format = @doc.formats[name]
node = format.add(node, value) if format?
return node
, node)
[prevNode, nextNode] = dom(leaf.node).split(leafOffset)
nextNode = dom(nextNode).splitBefore(@node).get() if nextNode
@node.insertBefore(node, nextNode)
this.rebuild()

insertEmbed: (offset, attributes) ->
[leaf, leafOffset] = this.findLeafAt(offset)
[prevNode, nextNode] = dom(leaf.node).split(leafOffset)
formatName = _.find(Object.keys(attributes), (name) =>
return @doc.formats[name].isType(Format.types.EMBED)
)
node = @doc.formats[formatName].add({}, attributes[formatName]) # TODO fix {} hack
attributes = _.clone(attributes)
delete attributes[formatName]
this._insert(offset, node, attributes)

insertText: (offset, text, formats = {}) ->
return unless text.length > 0
[leaf, leafOffset] = this.findLeafAt(offset)
# offset > 0 for multicursor
if _.isEqual(leaf.formats, formats) and text != dom.EMBED_TEXT
if _.isEqual(leaf.formats, formats)
leaf.insertText(leafOffset, text)
this.resetContent()
else
node = _.reduce(formats, (node, value, name) =>
format = @doc.formats[name]
node = format.add(node, value) if format?
return node
, document.createTextNode(text))
[prevNode, nextNode] = dom(leaf.node).split(leafOffset)
nextNode = dom(nextNode).splitBefore(@node).get() if nextNode
@node.insertBefore(node, nextNode)
this.rebuild()
this._insert(offset, document.createTextNode(text), formats)

optimize: ->
Normalizer.optimizeLine(@node)
Expand Down
4 changes: 3 additions & 1 deletion src/quill.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,9 @@ class Quill extends EventEmitter2
).join('')

insertEmbed: (index, type, url, source) ->
this.insertText(index, dom.EMBED_TEXT, type, url, source)
[index, end, formats, source] = this._buildParams(index, 0, type, url, source)
delta = new Delta().retain(index).insert(1, formats)
@editor.applyDelta(delta, source)

insertText: (index, text, name, value, source) ->
[index, end, formats, source] = this._buildParams(index, 0, name, value, source)
Expand Down
37 changes: 30 additions & 7 deletions test/unit/core/editor.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,6 @@ describe('Editor', ->
expect(@editor.root).toEqualHTML('<div><img src="http://quilljs.com/images/cloud.png"><b>A</b></div>', true)
)

it('insert image after image', ->
@editor.doc.setHTML('<div><img src="http://quilljs.com/images/cloud.png"></div>')
@editor._insertAt(0, Quill.Lib.DOM.EMBED_TEXT, { image: "http://quilljs.com/images/cloud.png" })
@editor.doc.optimizeLines()
expect(@editor.root).toEqualHTML('<div><img src="http://quilljs.com/images/cloud.png"><img src="http://quilljs.com/images/cloud.png"></div>', true)
)

it('insert newline after bullet', ->
@editor.doc.setHTML('<ul><li>One</li></ul>')
@editor._insertAt(1, '\n')
Expand All @@ -214,6 +207,36 @@ describe('Editor', ->
)
)

describe('insertEmbed()', ->
it('insert image', ->
@editor.doc.setHTML('<div>A</div>')
@editor._insertEmbed(1, { image: "http://quilljs.com/images/cloud.png" })
@editor.doc.optimizeLines()
expect(@editor.root).toEqualHTML('<div>A<img src="http://quilljs.com/images/cloud.png"></div>', true)
)

it('insert link image', ->
@editor.doc.setHTML('<div>A</div>')
@editor._insertEmbed(1, { image: "http://quilljs.com/images/cloud.png", link: "#" })
@editor.doc.optimizeLines()
expect(@editor.root).toEqualHTML('<div>A<a href="#"><img src="http://quilljs.com/images/cloud.png"></a></div>', true)
)

it('insert link image merge', ->
@editor.doc.setHTML('<div><a href="#">A</a></div>')
@editor._insertEmbed(1, { image: "http://quilljs.com/images/cloud.png", link: "#" })
@editor.doc.optimizeLines()
expect(@editor.root).toEqualHTML('<div><a href="#">A<img src="http://quilljs.com/images/cloud.png"></a></div>', true)
)

it('insert image after image', ->
@editor.doc.setHTML('<div><img src="http://quilljs.com/images/cloud.png"></div>')
@editor._insertEmbed(1, { image: "http://quilljs.com/images/cloud.png" })
@editor.doc.optimizeLines()
expect(@editor.root).toEqualHTML('<div><img src="http://quilljs.com/images/cloud.png"><img src="http://quilljs.com/images/cloud.png"></div>', true)
)
)

describe('applyDelta()', ->
tests =
'insert formatted':
Expand Down
10 changes: 6 additions & 4 deletions test/unit/core/format.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ describe('Format', ->
image:
format: new Quill.Format(Quill.Format.FORMATS.image)
existing: '<img src="http://quilljs.com/images/cloud.png">'
missing: 'Text'
removed: Quill.Lib.DOM.EMBED_TEXT
missing: '<br>'
removed: ''
value: 'http://quilljs.com/images/cloud.png'
link:
format: new Quill.Format(Quill.Format.FORMATS.link)
Expand Down Expand Up @@ -119,7 +119,8 @@ describe('Format', ->
it("#{name} add falsy value to existing", ->
@container.innerHTML = test.existing
test.format.add(@container.firstChild, false)
expect(@container).toEqualHTML(test.removed or test.missing)
expected = if test.removed? then test.removed else test.missing
expect(@container).toEqualHTML(expected)
)

it("#{name} add falsy value to missing", ->
Expand Down Expand Up @@ -178,7 +179,8 @@ describe('Format', ->
it("#{name} existing", ->
@container.innerHTML = test.existing
test.format.remove(@container.firstChild)
expect(@container).toEqualHTML(test.removed or test.missing)
expected = if test.removed? then test.removed else test.missing
expect(@container).toEqualHTML(expected)
)

it("#{name} missing", ->
Expand Down
2 changes: 1 addition & 1 deletion test/unit/core/line.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ describe('Line', ->
args: [0, 4, 'bold', false]
'remove image':
initial: '<b>01</b><img src="http://quilljs.com/images/cloud.png"><s>34</s>'
expected: "<b>01</b>#{dom.EMBED_TEXT}<s>34</s>"
expected: "<b>01</b><s>34</s>"
args: [2, 1, 'image', false]
'change format':
initial: '<b style="color: red;">012</b>'
Expand Down
2 changes: 1 addition & 1 deletion test/unit/core/selection.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ describe('Selection', ->
</div>'
quill = new Quill(@container.firstChild)
quill.editor.selection.setRange(new Quill.Lib.Range(0, 3))
quill.editor._insertAt(0, Quill.Lib.DOM.EMBED_TEXT, { image: 'http://quilljs.com/images/cloud.png' })
quill.editor._insertEmbed(0, { image: 'http://quilljs.com/images/cloud.png' })
quill.editor._formatAt(2, 4, 'bold', true)
expect(quill.root).toEqualHTML('
<div><img src="http://quilljs.com/images/cloud.png"><br></div>
Expand Down

0 comments on commit 3b3bead

Please sign in to comment.