Skip to content

Commit

Permalink
Switch to gulf v5 API
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelklehr committed Oct 5, 2016
1 parent 71bb896 commit 7c7b56f
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 65 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
lib/
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
# gulf-contenteditable
Convenient [gulf](http://github.com/marcelklehr/gulf#readme) wrapper for contenteditable elements
# gulf-editor-contenteditable
[Gulf](http://github.com/marcelklehr/gulf#readme) bindings for contenteditable elements

## Install

```
npm install gulf-contenteditable
npm install --save gulf gulf-editor-contenteditable dom-ot
```

## Usage

```
var bindEditor = require('gulf-contenteditable')
const domOT = require('dom-ot')
const ContenteditableDocument = require('gulf-editor-contenteditable')
var editable = document.querySelecor('#doc[contenteditable]')
var doc = bindEditor(editable)
var doc = new ContenteditableDocument({
storageAdapter: new gulf.MemoryAdapter
, ottype: domOT
, editorInstance: editable
})
```

## API
### bindEditor(editable:DOMElement, [storageAdapter])
* `editable` -- a contenteditable Element to be wired up with gulf
### class ContenteditableDocument({editorInstance:HTMLElement,...}) extends gulf.EditableDocument
* `contenteditable` -- a contenteditable Element to be wired up with gulf
* `storageAdapter` -- a gulf storage adapter (optional; defaults to the in-memory Adapter)
* *returns* the `gulf.EditableDocument` (see [the gulf docs](http://github.com/marcelklehr/gulf#readme))
* `ottype` -- the OT type, with this binding you'll want `dom-ot`


## Legal
(c) 2015 by Marcel Klehr

GNU Lesser General Public License
GNU Lesser General Public License
32 changes: 24 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
{
"name": "gulf-contenteditable",
"version": "4.0.1",
"name": "gulf-editor-contenteditable",
"version": "5.0.0",
"description": "Convenient gulf wrapper for contenteditable elements (uses dom-ot)",
"main": "index.js",
"main": "lib/index.js",
"dependencies": {
"mutation-summary": "^0.0.0"
"mutation-summary": "^0.0.0",
"babel-runtime": "^6.11.6",
"core-js": "2.x"
},
"peerDependencies": {
"gulf": "4.x",
"gulf": "5.x",
"dom-ot": "2.x"
},
"scripts": {
"build": "babel src --out-dir lib"
},
"babel": {
"presets": [
"es2015"
],
"plugins": ["transform-runtime"]
},
"devDependencies": {
"babel-cli": "6.x",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "6.x"
},
"repository": {
"type": "git",
"url": "git+https://github.com/marcelklehr/gulf-contenteditable.git"
"url": "git+https://github.com/marcelklehr/gulf-editor-contenteditable.git"
},
"keywords": [
"operational transformation",
Expand All @@ -22,7 +38,7 @@
"author": "Marcel Klehr <[email protected]>",
"license": "LGPL-3.0",
"bugs": {
"url": "https://github.com/marcelklehr/gulf-contenteditable/issues"
"url": "https://github.com/marcelklehr/gulf-editor-contenteditable/issues"
},
"homepage": "https://github.com/marcelklehr/gulf-contenteditable#readme"
"homepage": "https://github.com/marcelklehr/gulf-editor-contenteditable#readme"
}
105 changes: 57 additions & 48 deletions index.js → src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* gulf-contenteditable
* Copyright (C) 2015 Marcel Klehr <[email protected]>
* gulf-editor-contenteditable
* Copyright (C) 2015-2016 Marcel Klehr <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
Expand All @@ -18,70 +18,79 @@
var gulf = require('gulf')
, domOT = require('dom-ot')
, MutationSummary = require('mutation-summary')

module.exports = function(contenteditable) {
var doc = new gulf.EditableDocument(new gulf.MemoryAdapter, domOT)
doc.rootNode = contenteditable

doc._setContents = function(newcontent, cb) {
observer.disconnect()
contenteditable.innerHTML = ''
class ContenteditableDocument extends gulf.EditableDocument {
constructor(opts) {
super(opts)
if (!opts.editorInstance) throw new Error('No contenteditable HTMLElement passed')
this.rootNode = opts.editorInstance

this.mutationSummary = new MutationSummary({
rootNode: this.rootNode, // (defaults to window.document)
oldPreviousSibling: true,
queries: [
{ all: true}
],
callback: (summaries) => this.onLocalChange(summaries)
})
}

close() {
super.close()
this.mutationSummary.disconnect()
}

_onLocalChange(summaries) {
var ops = domOT.adapters.mutationSummary.import(summaries[0], this.rootNode)
ops = ops.filter(function(op) {
// filter out changes to the root node
if(op.path) return !!op.path.length
else return true
})
if(!ops.length) return

this.submitChange(ops)
ops.forEach(function(op) {
op.apply(this.rootNode, /*index:*/true, /*dry:*/true)
})
}

_setContent(newcontent) {
this.mutationSummary.disconnect()

this.rootNode.innerHTML = ''
for(var i=0; i<newcontent.childNodes.length; i++) {
contenteditable.appendChild(newcontent.childNodes[i].cloneNode(/*deep:*/true))
this.rootNode.appendChild(newcontent.childNodes[i].cloneNode(/*deep:*/true))
}

domOT.adapters.mutationSummary.createIndex(contenteditable)
observer.reconnect()
cb()
this.mutationSummary.reconnect()

return Promise.resolve()
}

doc._change = function(changes, cb) {
_onChange(changes) {
observer.disconnect()
console.log('_change', changes)

var ops = domOT.unpackOps(changes)
retainSelection(doc.rootNode, ops, function() {
ops.forEach(function(op) {
op.apply(contenteditable, /*index:*/true)
retainSelection(this.rootNode, ops, () => {
ops.forEach((op) => {
op.apply(this.rootNode, /*index:*/true)
})
})

observer.reconnect()
cb()
}

doc._collectChanges = function(cb) {
// changes are automatically collected by MutationSummary
cb()
return Promise.resolve()
}

var observer = new MutationSummary({
rootNode: contenteditable, // (defaults to window.document)
oldPreviousSibling: true,
queries: [
{ all: true}
],
callback: onChange
})
doc.mutationSummary = observer

function onChange(summaries) {
var ops = domOT.adapters.mutationSummary.import(summaries[0], contenteditable)
ops = ops.filter(function(op) {
// filter out changes to the root node
if(op.path) return !!op.path.length
else return true
})
if(!ops.length) return
console.log(ops)
doc.update(ops)
ops.forEach(function(op) {
op.apply(contenteditable, /*index:*/true, /*dry:*/true)
})
_onBeforeChange() {
return Promise.resolve()
}

return doc
}

module.export = ContenteditableDocument

function retainSelection(rootNode, ops, fn) {
var selection = rootNode.ownerDocument.defaultView.getSelection()
, ranges = []
Expand All @@ -97,4 +106,4 @@ function retainSelection(rootNode, ops, fn) {
if(r.endContainer) range.setEnd(r.endContainer, r.endOffset)
selection.addRange(range)
})
}
}

0 comments on commit 7c7b56f

Please sign in to comment.