Skip to content

Commit

Permalink
Cleanup
Browse files Browse the repository at this point in the history
 * Remove Marker#offsetInParent, add Markerable#offsetOfMarker
 * remove createBlankX methods from post node builder
 * Refactor List commands to work with embed intent
 * Test for inserting a list
  • Loading branch information
bantic committed Aug 31, 2015
1 parent f38f229 commit 9fa15e4
Show file tree
Hide file tree
Showing 18 changed files with 304 additions and 326 deletions.
66 changes: 31 additions & 35 deletions src/js/commands/list.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,36 @@
import TextFormatCommand from './text-format';
import { getSelectionBlockElement, selectNode, getSelectionTagName } from '../utils/selection-utils';
import { inherit } from 'content-kit-utils';

function ListCommand(options) {
TextFormatCommand.call(this, options);
}
inherit(ListCommand, TextFormatCommand);

ListCommand.prototype.exec = function() {
ListCommand._super.prototype.exec.call(this);

// After creation, lists need to be unwrapped
// TODO: eventually can remove this when direct model manipulation is ready
var listElement = getSelectionBlockElement();
var wrapperNode = listElement.parentNode;
if (wrapperNode.firstChild === listElement) {
var editorNode = wrapperNode.parentNode;
editorNode.insertBefore(listElement, wrapperNode);
editorNode.removeChild(wrapperNode);
selectNode(listElement);
export default class ListCommand extends TextFormatCommand {
constructor(editor, options) {
super(options);
this.editor = editor;
}

isActive() {
return false;
}
};

ListCommand.prototype.checkAutoFormat = function(node) {
// Creates unordered lists when node starts with '- '
// or ordered list if node starts with '1. '
var regex = this.autoFormatRegex, text;
if (node && regex) {
text = node.textContent;
if ('li' !== getSelectionTagName() && regex.test(text)) {
this.exec();
window.getSelection().anchorNode.textContent = text.replace(regex, '');
return true;
}

exec() {
const { editor } = this,
{ cursor } = editor;

const { head: {section:currentSection} } = cursor.offsets;

const listItem = editor.run(postEditor => {
const { builder } = postEditor;
const tagName = this.tag;
const listSection = builder.createListSection(tagName);
const listItem = builder.createListItem();
listSection.items.append(listItem);

postEditor.replaceSection(currentSection, listSection);
return listItem;
});

editor.cursor.moveToSection(listItem);
}
return false;
};

export default ListCommand;
unexec() {
throw new Error('Cannot unexec a ListCommand');
}
}
20 changes: 8 additions & 12 deletions src/js/commands/ordered-list.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import ListCommand from './list';
import { inherit } from 'content-kit-utils';

function OrderedListCommand() {
ListCommand.call(this, {
name: 'ordered list',
tag: 'ol',
action: 'insertOrderedList'
});
export default class UnorderedListCommand extends ListCommand {
constructor(editor) {
super(editor, {
name: 'Ordered List',
tag: 'ol',
button: '<i>ol</i>'
});
}
}
inherit(OrderedListCommand, ListCommand);

OrderedListCommand.prototype.autoFormatRegex = /^1\.\s/;

export default OrderedListCommand;
20 changes: 8 additions & 12 deletions src/js/commands/unordered-list.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
import ListCommand from './list';
import { inherit } from 'content-kit-utils';

function UnorderedListCommand() {
ListCommand.call(this, {
name: 'list',
tag: 'ul',
action: 'insertUnorderedList'
});
export default class UnorderedListCommand extends ListCommand {
constructor(editor) {
super(editor, {
name: 'Unordered List',
tag: 'ul',
button: '<i>ul</i>'
});
}
}
inherit(UnorderedListCommand, ListCommand);

UnorderedListCommand.prototype.autoFormatRegex = /^[-*]\s/;

export default UnorderedListCommand;
41 changes: 20 additions & 21 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,7 @@ const defaults = {
textFormatCommands: [
new LinkCommand()
],
embedCommands: [
new ImageCommand(),
new CardCommand()
],
autoTypingCommands: [
new UnorderedListCommand(),
new OrderedListCommand()
],
autoTypingCommands: [],
cards: [],
cardOptions: {},
unknownCardHandler: () => {
Expand Down Expand Up @@ -184,17 +177,6 @@ function bindDragAndDrop(editor) {
});
}

function initEmbedCommands(editor) {
var commands = editor.embedCommands;
if(commands) {
editor.addView(new EmbedIntent({
editorContext: editor,
commands: commands,
rootElement: editor.element
}));
}
}

function makeButtons(editor) {
const headingCommand = new HeadingCommand(editor);
const headingButton = new ReversibleToolbarButton(headingCommand, editor);
Expand Down Expand Up @@ -315,7 +297,8 @@ class Editor {
bindSelectionEvent(this);
bindKeyListeners(this);
this.addEventListener(element, 'input', () => this.handleInput());
initEmbedCommands(this);

this._initEmbedCommands();

this.addView(new TextFormatToolbar({
editor: this,
Expand Down Expand Up @@ -385,7 +368,8 @@ class Editor {
return;
}
}
cursorSection = postEditor.splitSection(offsets)[1];
const headPosition = offsets.head;
cursorSection = postEditor.splitSection(headPosition)[1];
});
this.cursor.moveToSection(cursorSection);
}
Expand Down Expand Up @@ -637,6 +621,21 @@ class Editor {
didRender(callback) {
this._didRenderCallbacks.push(callback);
}

_initEmbedCommands() {
const commands = [
new ImageCommand(),
new CardCommand(),
new UnorderedListCommand(this),
new OrderedListCommand(this)
];

this.addView(new EmbedIntent({
editorContext: this,
commands: commands,
rootElement: this.element
}));
}
}

mixin(Editor, EventEmitter);
Expand Down
32 changes: 18 additions & 14 deletions src/js/editor/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ class PostEditor {
*/
_deleteForwardFrom({marker, offset}) {
const nextCursorSection = marker.section,
nextCursorOffset = marker.offsetInParent(offset);
nextCursorOffset = nextCursorSection.offsetOfMarker(marker, offset);

if (offset === marker.length) {
const nextMarker = marker.next;
Expand Down Expand Up @@ -307,7 +307,7 @@ class PostEditor {
*/
_deleteBackwardFrom({marker, offset}) {
let nextCursorSection = marker.section,
nextCursorOffset = marker.offsetInParent(offset);
nextCursorOffset = nextCursorSection.offsetOfMarker(marker, offset);

if (offset === 0) {
const prevMarker = marker.prev;
Expand Down Expand Up @@ -336,7 +336,7 @@ class PostEditor {
nextCursorSection = prevSection;

if (beforeMarker) {
nextCursorOffset = beforeMarker.offsetInParent(beforeMarker.length);
nextCursorOffset = prevSection.offsetOfMarker(beforeMarker, beforeMarker.length);
} else {
nextCursorOffset = 0;
}
Expand Down Expand Up @@ -491,20 +491,16 @@ class PostEditor {
*
* The return value will be the two new sections. One or both of these
* sections can be blank (contain only a blank marker), for example if the
* headMaOffset is 0.
* headMarkerOffset is 0.
*
* @method splitMarkers
* @param {Object} markerRange Object with offsets, {headSection, headSectionOffset}
* @return {Array} of new sections, one for the first half and one for the second
* @method splitSection
* @param {Position} position
* @return {Array} new sections, one for the first half and one for the second
* @public
*/
splitSection({headSection: section, headSectionOffset}) {
let {
marker: headMarker,
offset: headMarkerOffset
} = section.markerPositionAtOffset(headSectionOffset);

const [beforeSection, afterSection] = section.splitAtMarker(headMarker, headMarkerOffset);
splitSection(position) {
const section = position.section;
const [beforeSection, afterSection] = section.splitAtPosition(position);
this._coalesceMarkers(beforeSection);
this._coalesceMarkers(afterSection);

Expand All @@ -530,6 +526,14 @@ class PostEditor {
return newSections;
}

/**
* @public
* FIXME: add tests for this
*/
replaceSection(section, newSection) {
return this._replaceSection(section, [newSection]);
}

_replaceSection(section, newSections) {
let nextSection = section.next;
let collection = section.parent.sections;
Expand Down
35 changes: 30 additions & 5 deletions src/js/models/_markerable.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,31 @@ export default class Markerable extends LinkedItem {
return !markerWithLength;
}

/**
* @param {Marker}
* @param {Number} markerOffset The offset relative to the start of the marker
*
* @return {Number} The offset relative to the start of this section
*/
offsetOfMarker(marker, markerOffset) {
if (marker.section !== this) {
throw new Error(`Cannot get offsetOfMarker for marker that is not child of this`);
}
// FIXME it is possible, when we get a cursor position before having finished reparsing,
// for markerOffset to be > marker.length. We shouldn't rely on this functionality.

let offset = 0;
let currentMarker = this.markers.head;
while (currentMarker && currentMarker !== marker.next) {
let length = currentMarker === marker ? markerOffset :
currentMarker.length;
offset += length;
currentMarker = currentMarker.next;
}

return offset;
}

/**
* Splits the marker at the offset, filters empty markers from the result,
* and replaces this marker with the new non-empty ones
Expand All @@ -43,11 +68,6 @@ export default class Markerable extends LinkedItem {
splitMarker(marker, offset, endOffset=marker.length) {
const newMarkers = filter(marker.split(offset, endOffset), m => !m.isEmpty);
this.markers.splice(marker, 1, newMarkers);
if (this.markers.length === 0) {
let blankMarker = this.builder.createBlankMarker();
this.markers.append(blankMarker);
newMarkers.push(blankMarker);
}
return newMarkers;
}

Expand Down Expand Up @@ -75,6 +95,11 @@ export default class Markerable extends LinkedItem {
throw new Error('splitAtMarker must be implemented by sub-class');
}

splitAtPosition(position) {
const {marker, offsetInMarker} = position;
return this.splitAtMarker(marker, offsetInMarker);
}

markerPositionAtOffset(offset) {
let currentOffset = 0;
let currentMarker;
Expand Down
3 changes: 2 additions & 1 deletion src/js/models/list-section.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { normalizeTagName } from '../utils/dom-utils';
import LinkedList from '../utils/linked-list';

export const DEFAULT_TAG_NAME = 'ul';
export const LIST_SECTION_TYPE = 'list-section';

export default class ListSection {
constructor(tagName, items=[]) {
constructor(tagName=DEFAULT_TAG_NAME, items=[]) {
this.tagName = normalizeTagName(tagName);
this.type = LIST_SECTION_TYPE;

Expand Down
26 changes: 0 additions & 26 deletions src/js/models/marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,32 +50,6 @@ const Marker = class Marker extends LinkedItem {
this.markups.push(markup);
}

// find the value of the absolute offset in this marker's parent section
offsetInParent(offset) {
const parent = this.section;
const markers = parent.markers;

let foundMarker = false;
let parentOffset = 0;
let marker = markers.head;
var length;
while (marker && !foundMarker) {
length = marker.length;
if (marker === this) {
foundMarker = true;
length = offset;
}

parentOffset += length;
marker = marker.next;
}

if (!foundMarker) {
throw new Error('offsetInParent could not find offset for marker');
}
return parentOffset;
}

removeMarkup(markup) {
const index = this.markups.indexOf(markup);
if (index !== -1) {
Expand Down
1 change: 1 addition & 0 deletions src/js/models/markup-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ const MarkupSection = class MarkupSection extends Markerable {

return this._redistributeMarkers(beforeSection, afterSection, marker, offset);
}

};

export default MarkupSection;
Loading

0 comments on commit 9fa15e4

Please sign in to comment.