Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit deb790a

Browse files
committed
Start the Marker type
1 parent 421fa4c commit deb790a

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed

lib/atom/marker.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import {Disposable} from 'event-kit';
4+
import {Range, Point} from 'atom';
5+
6+
import {autobind} from '../helpers';
7+
import {RefHolderPropType} from '../prop-types';
8+
import RefHolder from '../models/ref-holder';
9+
10+
const MarkablePropType = PropTypes.shape({
11+
markBufferRange: PropTypes.func.isRequired,
12+
markScreenRange: PropTypes.func.isRequired,
13+
markBufferPosition: PropTypes.func.isRequired,
14+
markScreenPosition: PropTypes.func.isRequired,
15+
});
16+
17+
const RangePropType = PropTypes.oneOfType([
18+
PropTypes.array,
19+
PropTypes.instanceOf(Range),
20+
]);
21+
22+
const PointPropType = PropTypes.oneOfType([
23+
PropTypes.array,
24+
PropTypes.instanceOf(Point),
25+
]);
26+
27+
const markerProps = {
28+
maintainHistory: PropTypes.bool,
29+
reversed: PropTypes.bool,
30+
invalidate: PropTypes.oneOf(['never', 'surround', 'overlap', 'inside', 'touch']),
31+
};
32+
33+
class WrappedMarker extends React.Component {
34+
static propTypes = {
35+
...markerProps,
36+
bufferRange: RangePropType,
37+
bufferPosition: PointPropType,
38+
screenRange: RangePropType,
39+
screenPosition: PointPropType,
40+
markableHolder: RefHolderPropType,
41+
children: PropTypes.element,
42+
handleID: PropTypes.func,
43+
}
44+
45+
static defaultProps = {
46+
handleID: () => {},
47+
}
48+
49+
constructor(props) {
50+
super(props);
51+
52+
autobind(this, 'createMarker');
53+
54+
this.sub = new Disposable();
55+
this.marker = null;
56+
}
57+
58+
componentDidMount() {
59+
this.observeMarkable();
60+
}
61+
62+
render() {
63+
return this.props.children || null;
64+
}
65+
66+
componentDidUpdate(prevProps) {
67+
if (this.props.markableHolder !== prevProps.markableHolder) {
68+
this.observeMarkable();
69+
}
70+
}
71+
72+
componentWillUnmount() {
73+
if (this.marker) {
74+
this.marker.destroy();
75+
}
76+
this.sub.dispose();
77+
}
78+
79+
observeMarkable() {
80+
this.sub.dispose();
81+
this.sub = this.props.markableHolder.observe(this.createMarker);
82+
}
83+
84+
createMarker() {
85+
if (this.marker) {
86+
this.marker.destroy();
87+
}
88+
89+
const options = Object.keys(markerProps).reduce((opts, propName) => {
90+
if (this.props[propName] !== undefined) {
91+
opts[propName] = this.props[propName];
92+
}
93+
return opts;
94+
}, {});
95+
96+
this.marker = this.props.markableHolder.map(markable => {
97+
if (this.props.bufferRange) {
98+
return markable.markBufferRange(this.props.bufferRange, options);
99+
}
100+
101+
if (this.props.screenRange) {
102+
return markable.markScreenRange(this.props.screenRange, options);
103+
}
104+
105+
if (this.props.bufferPosition) {
106+
return markable.markBufferPosition(this.props.bufferPosition, options);
107+
}
108+
109+
if (this.props.screenPosition) {
110+
return markable.markScreenPosition(this.props.screenPosition, options);
111+
}
112+
113+
throw new Error('Expected one of bufferRange, screenRange, bufferPosition, or screenPosition to be set');
114+
}).getOr(null);
115+
116+
if (this.marker) {
117+
this.props.handleID(this.marker.id);
118+
}
119+
}
120+
}
121+
122+
export default class Marker extends React.Component {
123+
static propTypes = {
124+
editor: MarkablePropType,
125+
layer: MarkablePropType,
126+
}
127+
128+
constructor(props) {
129+
super(props);
130+
131+
this.state = {
132+
markableHolder: RefHolder.on(props.layer || props.editor),
133+
};
134+
}
135+
136+
static getDerivedStateFromProps(props, state) {
137+
const markable = props.layer || props.editor;
138+
139+
if (state.markableHolder.map(m => m === markable).getOr(markable === undefined)) {
140+
return {};
141+
}
142+
143+
return {
144+
markableHolder: RefHolder.on(markable),
145+
};
146+
}
147+
148+
render() {
149+
if (!this.state.markableHolder.isEmpty()) {
150+
return <WrappedMarker markableHolder={this.state.markableHolder} {...this.props} />;
151+
}
152+
153+
return <WrappedMarker {...this.props} />;
154+
}
155+
}

test/atom/marker.test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import React from 'react';
2+
import {mount} from 'enzyme';
3+
4+
import Marker from '../../lib/atom/marker';
5+
import AtomTextEditor from '../../lib/atom/atom-text-editor';
6+
7+
describe('Marker', function() {
8+
let atomEnv, editor, markerID;
9+
10+
beforeEach(async function() {
11+
atomEnv = global.buildAtomEnvironment();
12+
editor = await atomEnv.workspace.open(__filename);
13+
});
14+
15+
function setMarkerID(id) {
16+
markerID = id;
17+
}
18+
19+
it('adds its marker on mount with default properties', function() {
20+
mount(
21+
<Marker editor={editor} bufferRange={[[0, 0], [10, 0]]} handleID={setMarkerID} />,
22+
);
23+
24+
const marker = editor.getMarker(markerID);
25+
assert.isTrue(marker.getBufferRange().isEqual([[0, 0], [10, 0]]));
26+
assert.strictEqual(marker.bufferMarker.invalidate, 'overlap');
27+
assert.isFalse(marker.isReversed());
28+
assert.isFalse(marker.bufferMarker.layer.maintainHistory);
29+
});
30+
31+
it('configures its marker');
32+
33+
it('prefers marking a MarkerLayer to a TextEditor');
34+
35+
it('removes its layer on unmount');
36+
37+
it('marks an editor from a parent node');
38+
39+
it('marks a marker layer from a parent node');
40+
});

0 commit comments

Comments
 (0)