Skip to content

Commit

Permalink
Add range#expandByMarker, list#detect with reverse
Browse files Browse the repository at this point in the history
  • Loading branch information
mixonic committed Nov 14, 2016
1 parent cf115f1 commit 254dfbc
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 6 deletions.
3 changes: 1 addition & 2 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import mobiledocRenderers from '../renderers/mobiledoc';
import { MOBILEDOC_VERSION } from 'mobiledoc-kit/renderers/mobiledoc';
import { mergeWithOptions } from '../utils/merge';
import { normalizeTagName, clearChildNodes } from '../utils/dom-utils';
import { forEach, filter, contains, values } from '../utils/array-utils';
import { forEach, filter, contains, values, detect } from '../utils/array-utils';
import { setData } from '../utils/element-utils';
import Cursor from '../utils/cursor';
import Range from '../utils/cursor/range';
Expand All @@ -22,7 +22,6 @@ import {
DEFAULT_KEY_COMMANDS, buildKeyCommand, findKeyCommands, validateKeyCommand
} from './key-commands';
import { CARD_MODES } from '../models/card';
import { detect } from '../utils/array-utils';
import assert from '../utils/assert';
import MutationHandler from 'mobiledoc-kit/editor/mutation-handler';
import EditHistory from 'mobiledoc-kit/editor/edit-history';
Expand Down
4 changes: 2 additions & 2 deletions src/js/utils/cursor/position.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ Position = class Position {
* @return {Range}
* @public
*/
toRange(tail=this) {
return new Range(this, tail);
toRange(tail=this, direction=null) {
return new Range(this, tail, direction);
}

get leafSectionIndex() {
Expand Down
34 changes: 34 additions & 0 deletions src/js/utils/cursor/range.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,40 @@ class Range {
}
}

/**
* expand a range to all markers matching a given check
*
* @param {Function} detectMarker
* @return {Range} The expanded range
*
* @public
*/
expandByMarker(detectMarker) {
let {
head,
tail,
direction
} = this;
let {section: headSection} = head;
if (headSection !== tail.section) {
throw new Error('#expandByMarker does not work across sections. Perhaps you should confirm the range is collapsed');
}

let firstNotMatchingDetect = i => {
return !detectMarker(i);
};

let headMarker = head.section.markers.detect(firstNotMatchingDetect, head.marker, true);
headMarker = (headMarker && headMarker.next) || head.marker;
let headPosition = new Position(headSection, headSection.offsetOfMarker(headMarker));

let tailMarker = tail.section.markers.detect(firstNotMatchingDetect, tail.marker);
tailMarker = (tailMarker && tailMarker.prev) || tail.marker;
let tailPosition = new Position(tail.section, tail.section.offsetOfMarker(tailMarker) + tailMarker.length);

return headPosition.toRange(tailPosition, direction);
}

_collapse(direction) {
return new Range(direction === DIRECTION.BACKWARD ? this.head : this.tail);
}
Expand Down
4 changes: 2 additions & 2 deletions src/js/utils/linked-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,12 @@ export default class LinkedList {
toArray() {
return this.readRange();
}
detect(callback, item=this.head) {
detect(callback, item=this.head, reverse=false) {
while (item) {
if (callback(item)) {
return item;
}
item = item.next;
item = reverse ? item.prev : item.next;
}
}
any(callback) {
Expand Down
33 changes: 33 additions & 0 deletions tests/unit/utils/cursor-range-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Helpers from '../../test-helpers';
import Range from 'mobiledoc-kit/utils/cursor/range';
import { DIRECTION } from 'mobiledoc-kit/utils/key';
import { detect } from '../utils/array-utils';

const { FORWARD, BACKWARD } = DIRECTION;
const {module, test} = Helpers;
Expand Down Expand Up @@ -187,3 +188,35 @@ test('#extend(0) returns same range', (assert) => {
assert.rangeIsEqual(collapsedRange.extend(0), collapsedRange, 'extending collapsed range 0 is no-op');
assert.rangeIsEqual(nonCollapsedRange.extend(0), nonCollapsedRange, 'extending non-collapsed range 0 is no-op');
});

test('#expandByMarker processed markers in a callback and continues as long as the callback returns true', (assert) => {
let post = Helpers.postAbstract.build(({post, markupSection, marker, markup}) => {
let bold = markup('b');
let italic = markup('i');
return post([
markupSection('p', [
marker('aiya', []),
marker('biya', [bold, italic]),
marker('ciya', [bold]),
marker('diya', [bold]),
])
]);
});

let section = post.sections.head;
let head = section.toPosition(9); // i in the third hiya
let tail = section.toPosition(15); // y in the last hiya
let range = head.toRange(tail);
let expandedRange = range.expandByMarker(marker => {
return !!(detect(marker.markups, markup => markup.tagName === 'b'));
});

assert.positionIsEqual(
expandedRange.head, section.toPosition(4),
'range head is start of second marker'
);
assert.positionIsEqual(
expandedRange.tail, section.toPosition(16),
'range tail did not change'
);
});
24 changes: 24 additions & 0 deletions tests/unit/utils/linked-list-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,30 @@ test(`#detect finds`, (assert) => {
assert.equal(list.detect(() => false), undefined, 'no item detected');
});

test(`#detect finds w/ start`, (assert) => {
let list = new LinkedList();
let itemOne = new LinkedItem();
let itemTwo = new LinkedItem();
let itemThree = new LinkedItem();
list.append(itemOne);
list.append(itemTwo);
list.append(itemThree);
assert.equal(list.detect(item => item === itemOne, itemOne), itemOne, 'itemOne detected');
assert.equal(list.detect(item => item === itemTwo, itemThree), null, 'no item detected');
});

test(`#detect finds w/ reverse`, (assert) => {
let list = new LinkedList();
let itemOne = new LinkedItem();
let itemTwo = new LinkedItem();
let itemThree = new LinkedItem();
list.append(itemOne);
list.append(itemTwo);
list.append(itemThree);
assert.equal(list.detect(item => item === itemOne, itemOne, true), itemOne, 'itemTwo detected');
assert.equal(list.detect(item => item === itemThree, itemThree, true), itemThree, 'itemThree');
});

test(`#objectAt looks up by index`, (assert) => {
let list = new LinkedList();
let itemOne = new LinkedItem();
Expand Down

0 comments on commit 254dfbc

Please sign in to comment.