Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add disableEditing, enableEditing #82

Merged
merged 1 commit into from
Aug 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ var editor = new ContentKit.Editor(element, options);
* `editor.serialize()` - serialize the current post for persistence. Returns
Mobiledoc.
* `editor.destroy()` - teardown the editor event listeners, free memory etc.
* `editor.disableEditing()` - stop the user from being able to edit the
current post with their cursor. Programmatic edits are still allowed.
* `editor.enableEditing()` - allow the user to make direct edits directly
to a post's text.

### Programmatic Post Editing

Expand Down
38 changes: 35 additions & 3 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ const defaults = {
spellcheck: true,
autofocus: true,
post: null,
serverHost: '',
// FIXME PhantomJS has 'ontouchstart' in window,
// causing the stickyToolbar to accidentally be auto-activated
// in tests
Expand All @@ -69,7 +68,9 @@ const defaults = {
],
cards: [],
cardOptions: {},
unknownCardHandler: () => { throw new Error('Unknown card encountered'); },
unknownCardHandler: () => {
throw new Error('Unknown card encountered');
},
mobiledoc: null
};

Expand Down Expand Up @@ -133,6 +134,9 @@ function bindSelectionEvent(editor) {
}

function bindKeyListeners(editor) {
if (!editor.isEditable) {
return;
}
editor.addEventListener(document, 'keyup', (event) => {
const key = Key.fromEvent(event);
if (key.isEscape()) {
Expand All @@ -141,6 +145,9 @@ function bindKeyListeners(editor) {
});

editor.addEventListener(document, 'keydown', (event) => {
if (!editor.isEditable) {
return;
}
const key = Key.fromEvent(event);

if (key.isDelete()) {
Expand Down Expand Up @@ -235,7 +242,7 @@ class Editor {
this.applyPlaceholder();

element.spellcheck = this.spellcheck;
element.setAttribute('contentEditable', true);
this.enableEditing();

if (this.mobiledoc) {
this.post = new MobiledocParser(this.builder).parse(this.mobiledoc);
Expand Down Expand Up @@ -602,6 +609,31 @@ class Editor {
this.removeAllViews();
}

/**
* Keep the user from directly editing the post. Modification via the
* programmatic API is still permitted.
*
* @method disableEditing
* @return undefined
* @public
*/
disableEditing() {
this.isEditable = false;
this.element.setAttribute('contentEditable', false);
}

/**
* Allow the user to directly interact with editing a post via a cursor.
*
* @method enableEditing
* @return undefined
* @public
*/
enableEditing() {
this.isEditable = true;
this.element.setAttribute('contentEditable', true);
}

/**
* Run a new post editing session. Yields a block with a new `postEditor`
* instance. This instance can be used to interact with the post abstract,
Expand Down
18 changes: 18 additions & 0 deletions tests/acceptance/basic-editor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,21 @@ test('sets element as contenteditable', (assert) => {
assert.equal(editorElement.firstChild.tagName, 'P',
`editor element has a P as its first child`);
});

test('#disableEditing and #enableEditing toggle contenteditable', (assert) => {
let innerHTML = `<p>Hello</p>`;
editorElement.innerHTML = innerHTML;
editor = new Editor(document.getElementById('editor'));

assert.equal(editorElement.getAttribute('contenteditable'),
'true',
'element is contenteditable');
editor.disableEditing();
assert.equal(editorElement.getAttribute('contenteditable'),
'false',
'element is not contenteditable');
editor.enableEditing();
assert.equal(editorElement.getAttribute('contenteditable'),
'true',
'element is contenteditable');
});
17 changes: 16 additions & 1 deletion tests/acceptance/editor-sections-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,22 @@ test('hitting enter at end of a section creates new empty section', (assert) =>
offset: 0});
});

test('deleting across 0 sections merges them', (assert) => {
// Phantom does not recognize toggling contenteditable off
Helpers.skipInPhantom('deleting across 2 sections does nothing if editing is disabled', (assert) => {
editor = new Editor(editorElement, {mobiledoc: mobileDocWith2Sections});
editor.disableEditing();
assert.equal($('#editor p').length, 2, 'precond - has 2 sections to start');

const p0 = $('#editor p:eq(0)')[0],
p1 = $('#editor p:eq(1)')[0];

Helpers.dom.selectText('tion', p0, 'sec', p1);
Helpers.dom.triggerDelete(editor);

assert.equal($('#editor p').length, 2, 'still has 2 sections');
});

test('deleting across 2 sections merges them', (assert) => {
editor = new Editor(editorElement, {mobiledoc: mobileDocWith2Sections});
assert.equal($('#editor p').length, 2, 'precond - has 2 sections to start');

Expand Down