@teselagen/ove 0.7.6-beta.3 → 0.7.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AlignmentView/index.d.ts +0 -4
- package/index.cjs.js +9929 -9549
- package/index.es.js +9923 -9543
- package/index.umd.js +9830 -8898
- package/package.json +6 -2
- package/src/AlignmentView/index.js +49 -77
- package/src/withEditorInteractions/index.js +74 -131
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teselagen/ove",
|
|
3
|
-
"version": "0.7.6
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"main": "./src/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@teselagen/sequence-utils": "0.3.27",
|
|
14
14
|
"@teselagen/range-utils": "0.3.7",
|
|
15
|
-
"@teselagen/ui": "0.7.10
|
|
15
|
+
"@teselagen/ui": "0.7.10",
|
|
16
16
|
"@teselagen/file-utils": "0.3.16",
|
|
17
17
|
"@teselagen/bounce-loader": "0.3.11",
|
|
18
18
|
"@teselagen/bio-parsers": "0.4.22",
|
|
19
|
+
"@blueprintjs/core": "3.54.0",
|
|
20
|
+
"@blueprintjs/datetime": "^3.24.1",
|
|
19
21
|
"@blueprintjs/icons": "3.33.0",
|
|
20
22
|
"@blueprintjs/select": "3.18.11",
|
|
21
23
|
"@dnd-kit/core": "^6.1.0",
|
|
@@ -69,6 +71,7 @@
|
|
|
69
71
|
"react-dom": "^18.3.1",
|
|
70
72
|
"react-draggable": "4.4.5",
|
|
71
73
|
"react-dropzone": "^11.4.2",
|
|
74
|
+
"react-markdown": "9.0.1",
|
|
72
75
|
"react-measure": "^2.5.2",
|
|
73
76
|
"react-redux": "^8.0.5",
|
|
74
77
|
"react-rnd": "^10.2.4",
|
|
@@ -80,6 +83,7 @@
|
|
|
80
83
|
"redux-act": "^1.8.0",
|
|
81
84
|
"redux-form": "^8.3.10",
|
|
82
85
|
"redux-thunk": "2.4.1",
|
|
86
|
+
"remark-gfm": "^4.0.0",
|
|
83
87
|
"reselect": "^4.1.7",
|
|
84
88
|
"shortid": "^2.2.16",
|
|
85
89
|
"tg-use-local-storage-state": "^16.0.3",
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
Droppable,
|
|
5
5
|
Draggable as DndDraggable
|
|
6
6
|
} from "@hello-pangea/dnd";
|
|
7
|
-
import ClipboardJS from "clipboard";
|
|
8
7
|
import React from "react";
|
|
9
8
|
import { connect } from "react-redux";
|
|
10
9
|
import {
|
|
@@ -104,6 +103,7 @@ export class AlignmentView extends React.Component {
|
|
|
104
103
|
this.handleAlignmentCopy
|
|
105
104
|
);
|
|
106
105
|
}
|
|
106
|
+
|
|
107
107
|
getMaxLength = () => {
|
|
108
108
|
const { alignmentTracks } = this.props;
|
|
109
109
|
const { sequenceData = { sequence: "" }, alignmentData } =
|
|
@@ -175,6 +175,7 @@ export class AlignmentView extends React.Component {
|
|
|
175
175
|
this.onShortcutCopy &&
|
|
176
176
|
document.removeEventListener("keydown", this.handleAlignmentCopy);
|
|
177
177
|
}
|
|
178
|
+
|
|
178
179
|
handleAlignmentCopy = event => {
|
|
179
180
|
if (
|
|
180
181
|
event.key === "c" &&
|
|
@@ -196,6 +197,7 @@ export class AlignmentView extends React.Component {
|
|
|
196
197
|
event.preventDefault();
|
|
197
198
|
}
|
|
198
199
|
};
|
|
200
|
+
|
|
199
201
|
getAllAlignmentsFastaText = () => {
|
|
200
202
|
const selectionLayer =
|
|
201
203
|
this.props.store.getState().VectorEditor.__allEditorsOptions.alignments[
|
|
@@ -214,6 +216,7 @@ export class AlignmentView extends React.Component {
|
|
|
214
216
|
});
|
|
215
217
|
return seqDataOfAllTracksToCopy.join("");
|
|
216
218
|
};
|
|
219
|
+
|
|
217
220
|
state = {
|
|
218
221
|
alignmentName: this.props.alignmentName,
|
|
219
222
|
isTrackDragging: false,
|
|
@@ -222,6 +225,7 @@ export class AlignmentView extends React.Component {
|
|
|
222
225
|
width: 0,
|
|
223
226
|
nameDivWidth: 140
|
|
224
227
|
};
|
|
228
|
+
|
|
225
229
|
easyStore = store({
|
|
226
230
|
selectionLayer: { start: -1, end: -1 },
|
|
227
231
|
caretPosition: -1,
|
|
@@ -280,6 +284,7 @@ export class AlignmentView extends React.Component {
|
|
|
280
284
|
}, 5000);
|
|
281
285
|
}
|
|
282
286
|
}
|
|
287
|
+
|
|
283
288
|
componentDidMount() {
|
|
284
289
|
const updateAlignmentSelection = newRangeOrCaret => {
|
|
285
290
|
this.updateSelectionOrCaret(false, newRangeOrCaret, {
|
|
@@ -1194,6 +1199,44 @@ export class AlignmentView extends React.Component {
|
|
|
1194
1199
|
|
|
1195
1200
|
const alignmentData = track.alignmentData;
|
|
1196
1201
|
const { name } = alignmentData;
|
|
1202
|
+
|
|
1203
|
+
const copySpecificAlignmentFasta = async () => {
|
|
1204
|
+
const { selectionLayer } =
|
|
1205
|
+
this.props.store.getState().VectorEditor
|
|
1206
|
+
.__allEditorsOptions.alignments[
|
|
1207
|
+
this.props.id
|
|
1208
|
+
] || {};
|
|
1209
|
+
const seqDataToCopy = getSequenceDataBetweenRange(
|
|
1210
|
+
alignmentData,
|
|
1211
|
+
selectionLayer
|
|
1212
|
+
).sequence;
|
|
1213
|
+
const seqDataToCopyAsFasta = `>${name}\r\n${seqDataToCopy}\r\n`;
|
|
1214
|
+
await navigator.clipboard.writeText(
|
|
1215
|
+
seqDataToCopyAsFasta
|
|
1216
|
+
);
|
|
1217
|
+
};
|
|
1218
|
+
|
|
1219
|
+
const copySpecificAlignment = async () => {
|
|
1220
|
+
const { selectionLayer } =
|
|
1221
|
+
this.props.store.getState().VectorEditor
|
|
1222
|
+
.__allEditorsOptions.alignments[
|
|
1223
|
+
this.props.id
|
|
1224
|
+
] || {};
|
|
1225
|
+
const seqDataToCopy = getSequenceDataBetweenRange(
|
|
1226
|
+
alignmentData,
|
|
1227
|
+
selectionLayer
|
|
1228
|
+
).sequence;
|
|
1229
|
+
await navigator.clipboard.writeText(
|
|
1230
|
+
seqDataToCopy
|
|
1231
|
+
);
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
const getAllAlignmentsFastaText = async () => {
|
|
1235
|
+
await navigator.clipboard.writeText(
|
|
1236
|
+
this.getAllAlignmentsFastaText()
|
|
1237
|
+
);
|
|
1238
|
+
};
|
|
1239
|
+
|
|
1197
1240
|
showContextMenu(
|
|
1198
1241
|
[
|
|
1199
1242
|
...(additionalSelectionLayerRightClickedOptions
|
|
@@ -1207,24 +1250,8 @@ export class AlignmentView extends React.Component {
|
|
|
1207
1250
|
className:
|
|
1208
1251
|
"copyAllAlignmentsFastaClipboardHelper",
|
|
1209
1252
|
hotkey: "cmd+c",
|
|
1210
|
-
willUnmount: () => {
|
|
1211
|
-
this
|
|
1212
|
-
.copyAllAlignmentsFastaClipboardHelper &&
|
|
1213
|
-
this.copyAllAlignmentsFastaClipboardHelper.destroy();
|
|
1214
|
-
},
|
|
1215
|
-
didMount: () => {
|
|
1216
|
-
this.copyAllAlignmentsFastaClipboardHelper =
|
|
1217
|
-
new ClipboardJS(
|
|
1218
|
-
`.copyAllAlignmentsFastaClipboardHelper`,
|
|
1219
|
-
{
|
|
1220
|
-
action: "copyAllAlignmentsFasta",
|
|
1221
|
-
text: () => {
|
|
1222
|
-
return this.getAllAlignmentsFastaText();
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
);
|
|
1226
|
-
},
|
|
1227
1253
|
onClick: () => {
|
|
1254
|
+
getAllAlignmentsFastaText();
|
|
1228
1255
|
window.toastr.success("Selection Copied");
|
|
1229
1256
|
}
|
|
1230
1257
|
},
|
|
@@ -1232,36 +1259,8 @@ export class AlignmentView extends React.Component {
|
|
|
1232
1259
|
text: `Copy Selection of ${name} as Fasta`,
|
|
1233
1260
|
className:
|
|
1234
1261
|
"copySpecificAlignmentFastaClipboardHelper",
|
|
1235
|
-
willUnmount: () => {
|
|
1236
|
-
this
|
|
1237
|
-
.copySpecificAlignmentFastaClipboardHelper &&
|
|
1238
|
-
this.copySpecificAlignmentFastaClipboardHelper.destroy();
|
|
1239
|
-
},
|
|
1240
|
-
didMount: () => {
|
|
1241
|
-
this.copySpecificAlignmentFastaClipboardHelper =
|
|
1242
|
-
new ClipboardJS(
|
|
1243
|
-
`.copySpecificAlignmentFastaClipboardHelper`,
|
|
1244
|
-
{
|
|
1245
|
-
action: "copySpecificAlignmentFasta",
|
|
1246
|
-
text: () => {
|
|
1247
|
-
const { selectionLayer } =
|
|
1248
|
-
this.props.store.getState()
|
|
1249
|
-
.VectorEditor
|
|
1250
|
-
.__allEditorsOptions.alignments[
|
|
1251
|
-
this.props.id
|
|
1252
|
-
] || {};
|
|
1253
|
-
const seqDataToCopy =
|
|
1254
|
-
getSequenceDataBetweenRange(
|
|
1255
|
-
alignmentData,
|
|
1256
|
-
selectionLayer
|
|
1257
|
-
).sequence;
|
|
1258
|
-
const seqDataToCopyAsFasta = `>${name}\r\n${seqDataToCopy}\r\n`;
|
|
1259
|
-
return seqDataToCopyAsFasta;
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
);
|
|
1263
|
-
},
|
|
1264
1262
|
onClick: () => {
|
|
1263
|
+
copySpecificAlignmentFasta();
|
|
1265
1264
|
window.toastr.success(
|
|
1266
1265
|
"Selection Copied As Fasta"
|
|
1267
1266
|
);
|
|
@@ -1271,35 +1270,8 @@ export class AlignmentView extends React.Component {
|
|
|
1271
1270
|
text: `Copy Selection of ${name}`,
|
|
1272
1271
|
className:
|
|
1273
1272
|
"copySpecificAlignmentAsPlainClipboardHelper",
|
|
1274
|
-
willUnmount: () => {
|
|
1275
|
-
this
|
|
1276
|
-
.copySpecificAlignmentAsPlainClipboardHelper &&
|
|
1277
|
-
this.copySpecificAlignmentAsPlainClipboardHelper.destroy();
|
|
1278
|
-
},
|
|
1279
|
-
didMount: () => {
|
|
1280
|
-
this.copySpecificAlignmentAsPlainClipboardHelper =
|
|
1281
|
-
new ClipboardJS(
|
|
1282
|
-
`.copySpecificAlignmentAsPlainClipboardHelper`,
|
|
1283
|
-
{
|
|
1284
|
-
action: "copySpecificAlignmentFasta",
|
|
1285
|
-
text: () => {
|
|
1286
|
-
const { selectionLayer } =
|
|
1287
|
-
this.props.store.getState()
|
|
1288
|
-
.VectorEditor
|
|
1289
|
-
.__allEditorsOptions.alignments[
|
|
1290
|
-
this.props.id
|
|
1291
|
-
] || {};
|
|
1292
|
-
const seqDataToCopy =
|
|
1293
|
-
getSequenceDataBetweenRange(
|
|
1294
|
-
alignmentData,
|
|
1295
|
-
selectionLayer
|
|
1296
|
-
).sequence;
|
|
1297
|
-
return seqDataToCopy;
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
);
|
|
1301
|
-
},
|
|
1302
1273
|
onClick: () => {
|
|
1274
|
+
copySpecificAlignment();
|
|
1303
1275
|
window.toastr.success("Selection Copied");
|
|
1304
1276
|
}
|
|
1305
1277
|
}
|
|
@@ -1313,7 +1285,7 @@ export class AlignmentView extends React.Component {
|
|
|
1313
1285
|
sequenceLength={sequenceLength}
|
|
1314
1286
|
charWidth={this.getCharWidthInLinearView()}
|
|
1315
1287
|
row={{ start: 0, end: sequenceLength - 1 }}
|
|
1316
|
-
|
|
1288
|
+
/>
|
|
1317
1289
|
<PerformantCaret
|
|
1318
1290
|
leftMargin={this.state.nameDivWidth}
|
|
1319
1291
|
className="veAlignmentSelectionLayer"
|
|
@@ -1679,7 +1651,7 @@ export class AlignmentView extends React.Component {
|
|
|
1679
1651
|
sequenceLength={sequenceLength}
|
|
1680
1652
|
charWidth={this.getMinCharWidth(true)}
|
|
1681
1653
|
row={{ start: 0, end: sequenceLength - 1 }}
|
|
1682
|
-
|
|
1654
|
+
/>
|
|
1683
1655
|
<PerformantCaret
|
|
1684
1656
|
style={{
|
|
1685
1657
|
opacity: 0.2
|
|
@@ -4,7 +4,6 @@ import {
|
|
|
4
4
|
getAminoAcidStringFromSequenceString
|
|
5
5
|
} from "@teselagen/sequence-utils";
|
|
6
6
|
import { getSequenceWithinRange } from "@teselagen/range-utils";
|
|
7
|
-
import ClipboardJS from "clipboard";
|
|
8
7
|
import { compose } from "redux";
|
|
9
8
|
import {
|
|
10
9
|
getReverseComplementSequenceAndAnnotations,
|
|
@@ -93,6 +92,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
93
92
|
return <ConnectedMenu {...props} {...p} />;
|
|
94
93
|
};
|
|
95
94
|
}
|
|
95
|
+
|
|
96
96
|
componentWillUnmount() {
|
|
97
97
|
this.combokeys && this.combokeys.detach();
|
|
98
98
|
}
|
|
@@ -183,6 +183,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
183
183
|
omitIcons: true
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
|
+
|
|
186
187
|
updateSelectionOrCaret = (shiftHeld, newRangeOrCaret) => {
|
|
187
188
|
const {
|
|
188
189
|
selectionLayer,
|
|
@@ -257,7 +258,8 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
257
258
|
e.preventDefault();
|
|
258
259
|
};
|
|
259
260
|
|
|
260
|
-
handleCutOrCopy = isCut => e => {
|
|
261
|
+
handleCutOrCopy = isCut => async e => {
|
|
262
|
+
e.preventDefault();
|
|
261
263
|
const {
|
|
262
264
|
onCopy = noop,
|
|
263
265
|
sequenceData,
|
|
@@ -303,7 +305,6 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
303
305
|
}`
|
|
304
306
|
);
|
|
305
307
|
|
|
306
|
-
const clipboardData = e.clipboardData;
|
|
307
308
|
const textToCopy =
|
|
308
309
|
(this.sequenceDataToCopy || {}).textToCopy !== undefined
|
|
309
310
|
? this.sequenceDataToCopy.textToCopy
|
|
@@ -312,9 +313,16 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
312
313
|
: seqData.sequence;
|
|
313
314
|
|
|
314
315
|
seqData.textToCopy = textToCopy;
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
316
|
+
await navigator.clipboard.writeText(textToCopy);
|
|
317
|
+
// application/json is not supported by clipboard api on browser
|
|
318
|
+
// await navigator.clipboard.write([
|
|
319
|
+
// new ClipboardItem({
|
|
320
|
+
// "application/json": new Blob([JSON.stringify(seqData)], {
|
|
321
|
+
// type: "application/json"
|
|
322
|
+
// }),
|
|
323
|
+
// "text/plain": new Blob([textToCopy], { type: "text/plain" })
|
|
324
|
+
// })
|
|
325
|
+
// ]);
|
|
318
326
|
|
|
319
327
|
if (isCut && !(readOnly || disableBpEditing) && !disableBpEditing) {
|
|
320
328
|
this.handleDnaDelete(false);
|
|
@@ -326,10 +334,8 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
326
334
|
}),
|
|
327
335
|
this.props
|
|
328
336
|
);
|
|
329
|
-
document.body.removeEventListener("cut", this.handleCut);
|
|
330
337
|
} else {
|
|
331
338
|
onCopy(e, seqData, this.props);
|
|
332
|
-
document.body.removeEventListener("copy", this.handleCopy);
|
|
333
339
|
}
|
|
334
340
|
window.toastr.success(
|
|
335
341
|
`Selection ${
|
|
@@ -340,6 +346,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
340
346
|
);
|
|
341
347
|
this.sequenceDataToCopy = undefined;
|
|
342
348
|
};
|
|
349
|
+
|
|
343
350
|
handleCut = this.handleCutOrCopy(true);
|
|
344
351
|
|
|
345
352
|
handleCopy = this.handleCutOrCopy();
|
|
@@ -358,6 +365,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
358
365
|
}
|
|
359
366
|
};
|
|
360
367
|
};
|
|
368
|
+
|
|
361
369
|
createDisableBpEditingMsg = () => {
|
|
362
370
|
window.toastr.warning(
|
|
363
371
|
typeof this.props.disableBpEditing === "string"
|
|
@@ -366,6 +374,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
366
374
|
this.getDuplicateAction()
|
|
367
375
|
);
|
|
368
376
|
};
|
|
377
|
+
|
|
369
378
|
createReadOnlyMsg = () => {
|
|
370
379
|
window.toastr.warning(
|
|
371
380
|
this.props.readOnly === "string"
|
|
@@ -486,6 +495,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
486
495
|
//we only call caretPositionUpdate if we're actually changing something
|
|
487
496
|
this.props.caretPositionUpdate(position);
|
|
488
497
|
};
|
|
498
|
+
|
|
489
499
|
selectionLayerUpdate = newSelection => {
|
|
490
500
|
const { selectionLayer = { start: -1, end: -1 }, ignoreGapsOnHighlight } =
|
|
491
501
|
this.props;
|
|
@@ -582,6 +592,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
582
592
|
annotationDeselectAll(undefined);
|
|
583
593
|
annotationSelect(annotation);
|
|
584
594
|
};
|
|
595
|
+
|
|
585
596
|
insertHelper = {
|
|
586
597
|
onClick: (e, ctxInfo) => {
|
|
587
598
|
this.handleDnaInsert({
|
|
@@ -593,75 +604,55 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
593
604
|
}
|
|
594
605
|
};
|
|
595
606
|
|
|
596
|
-
// eslint-disable-next-line no-unused-vars
|
|
597
607
|
getCopyOptions = annotation => {
|
|
598
608
|
const { sequenceData, readOnly, disableBpEditing, selectionLayer } =
|
|
599
609
|
this.props;
|
|
600
610
|
const { isProtein } = sequenceData;
|
|
601
|
-
const makeTextCopyable =
|
|
602
|
-
return
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
document.body.addEventListener("copy", this.handleCopy);
|
|
607
|
-
} else {
|
|
608
|
-
document.body.addEventListener("cut", this.handleCut);
|
|
609
|
-
}
|
|
610
|
-
const { editorName, store } = this.props;
|
|
611
|
-
const { sequenceData, copyOptions, selectionLayer } =
|
|
612
|
-
store.getState().VectorEditor[editorName];
|
|
611
|
+
const makeTextCopyable = transformFunc => {
|
|
612
|
+
return async () => {
|
|
613
|
+
const { editorName, store } = this.props;
|
|
614
|
+
const { sequenceData, copyOptions, selectionLayer } =
|
|
615
|
+
store.getState().VectorEditor[editorName];
|
|
613
616
|
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
617
|
+
const selectedSeqData = getSequenceDataBetweenRange(
|
|
618
|
+
sequenceData,
|
|
619
|
+
getSelFromWrappedAddon(
|
|
620
|
+
selectionLayer,
|
|
621
|
+
sequenceData.sequence.length
|
|
622
|
+
),
|
|
623
|
+
{
|
|
624
|
+
excludePartial: {
|
|
625
|
+
features: !copyOptions.partialFeatures,
|
|
626
|
+
parts: !copyOptions.partialParts
|
|
627
|
+
},
|
|
628
|
+
exclude: {
|
|
629
|
+
features: !copyOptions.features,
|
|
630
|
+
parts: !copyOptions.parts
|
|
629
631
|
}
|
|
630
|
-
);
|
|
631
|
-
const sequenceDataToCopy = transformFunc(
|
|
632
|
-
selectedSeqData,
|
|
633
|
-
sequenceData
|
|
634
|
-
);
|
|
635
|
-
this.sequenceDataToCopy = sequenceDataToCopy;
|
|
636
|
-
|
|
637
|
-
if (window.Cypress) {
|
|
638
|
-
window.Cypress.textToCopy = sequenceDataToCopy.textToCopy;
|
|
639
|
-
window.Cypress.seqDataToCopy = sequenceDataToCopy;
|
|
640
632
|
}
|
|
641
|
-
|
|
633
|
+
);
|
|
634
|
+
const sequenceDataToCopy = transformFunc(
|
|
635
|
+
selectedSeqData,
|
|
636
|
+
sequenceData
|
|
637
|
+
);
|
|
638
|
+
this.sequenceDataToCopy = sequenceDataToCopy;
|
|
639
|
+
|
|
640
|
+
if (window.Cypress) {
|
|
641
|
+
window.Cypress.textToCopy = sequenceDataToCopy.textToCopy;
|
|
642
|
+
window.Cypress.seqDataToCopy = sequenceDataToCopy;
|
|
642
643
|
}
|
|
643
|
-
}
|
|
644
|
+
};
|
|
644
645
|
};
|
|
645
646
|
const aaCopy = {
|
|
646
647
|
text: "Copy AA Sequence",
|
|
647
648
|
className: "openVeCopyAA",
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
? selectedSeqData.proteinSequence.toUpperCase()
|
|
655
|
-
: getAminoAcidStringFromSequenceString(selectedSeqData.sequence);
|
|
656
|
-
return {
|
|
657
|
-
...selectedSeqData,
|
|
658
|
-
textToCopy
|
|
659
|
-
};
|
|
660
|
-
}, className);
|
|
661
|
-
}
|
|
649
|
+
onClick: makeTextCopyable(selectedSeqData => ({
|
|
650
|
+
...selectedSeqData,
|
|
651
|
+
textToCopy: isProtein
|
|
652
|
+
? selectedSeqData.proteinSequence.toUpperCase()
|
|
653
|
+
: getAminoAcidStringFromSequenceString(selectedSeqData.sequence)
|
|
654
|
+
}))
|
|
662
655
|
};
|
|
663
|
-
// TODO: maybe stop using Clipboard.js and unify clipboard handling with
|
|
664
|
-
// a more versatile approach
|
|
665
656
|
return [
|
|
666
657
|
...(readOnly || disableBpEditing
|
|
667
658
|
? []
|
|
@@ -673,20 +664,7 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
673
664
|
{
|
|
674
665
|
text: "Cut",
|
|
675
666
|
className: "openVeCut",
|
|
676
|
-
|
|
677
|
-
this.openVeCut && this.openVeCut.destroy();
|
|
678
|
-
},
|
|
679
|
-
didMount: ({ className }) => {
|
|
680
|
-
// TODO: Maybe use a cut action instead
|
|
681
|
-
this.openVeCut = makeTextCopyable(
|
|
682
|
-
s => ({
|
|
683
|
-
...s,
|
|
684
|
-
textToCopy: isProtein ? s.proteinSequence : s.sequence
|
|
685
|
-
}),
|
|
686
|
-
className,
|
|
687
|
-
"cut"
|
|
688
|
-
);
|
|
689
|
-
}
|
|
667
|
+
onClick: this.handleCut
|
|
690
668
|
}
|
|
691
669
|
]),
|
|
692
670
|
{
|
|
@@ -699,80 +677,45 @@ function VectorInteractionHOC(Component /* options */) {
|
|
|
699
677
|
{
|
|
700
678
|
text: isProtein ? "Copy DNA Bps" : "Copy",
|
|
701
679
|
className: "openVeCopy2",
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
this.openVeCopy2 = makeTextCopyable(
|
|
707
|
-
s => ({ ...s, textToCopy: s.sequence }),
|
|
708
|
-
className
|
|
709
|
-
);
|
|
710
|
-
}
|
|
680
|
+
onClick: makeTextCopyable(s => ({
|
|
681
|
+
...s,
|
|
682
|
+
textToCopy: s.sequence
|
|
683
|
+
}))
|
|
711
684
|
},
|
|
712
685
|
|
|
713
686
|
{
|
|
714
687
|
text: "Copy Genbank For Selection",
|
|
715
688
|
className: "openVeCopyGenbankForSelection",
|
|
716
|
-
|
|
717
|
-
this.openVeCopyGenbankForSelection &&
|
|
718
|
-
this.openVeCopyGenbankForSelection.destroy();
|
|
719
|
-
},
|
|
720
|
-
didMount: ({ className }) => {
|
|
721
|
-
this.openVeCopyGenbankForSelection = makeTextCopyable(
|
|
722
|
-
getGenbankFromSelection,
|
|
723
|
-
className
|
|
724
|
-
);
|
|
725
|
-
}
|
|
689
|
+
onClick: makeTextCopyable(getGenbankFromSelection)
|
|
726
690
|
},
|
|
727
691
|
{
|
|
728
692
|
text: isProtein
|
|
729
693
|
? "Copy Reverse Complement DNA Bps"
|
|
730
694
|
: "Copy Reverse Complement",
|
|
731
695
|
className: "openVeCopyReverse",
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
didMount: ({ className }) => {
|
|
736
|
-
this.openVeCopyReverse = makeTextCopyable(
|
|
737
|
-
getReverseComplementSequenceAndAnnotations,
|
|
738
|
-
className
|
|
739
|
-
);
|
|
740
|
-
}
|
|
696
|
+
onClick: makeTextCopyable(
|
|
697
|
+
getReverseComplementSequenceAndAnnotations
|
|
698
|
+
)
|
|
741
699
|
},
|
|
742
700
|
...(isProtein ? [] : [aaCopy]),
|
|
743
701
|
{
|
|
744
702
|
text: "Copy Reverse Complement AA Sequence",
|
|
745
703
|
className: "openVeCopyAAReverse",
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
getReverseComplementSequenceAndAnnotations(selectedSeqData);
|
|
753
|
-
const textToCopy = isProtein
|
|
704
|
+
onClick: makeTextCopyable(selectedSeqData => {
|
|
705
|
+
const revSeqData =
|
|
706
|
+
getReverseComplementSequenceAndAnnotations(selectedSeqData);
|
|
707
|
+
return {
|
|
708
|
+
...revSeqData,
|
|
709
|
+
textToCopy: isProtein
|
|
754
710
|
? revSeqData.proteinSequence.toUpperCase()
|
|
755
|
-
: getAminoAcidStringFromSequenceString(revSeqData.sequence)
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
textToCopy
|
|
759
|
-
};
|
|
760
|
-
}, className);
|
|
761
|
-
}
|
|
711
|
+
: getAminoAcidStringFromSequenceString(revSeqData.sequence)
|
|
712
|
+
};
|
|
713
|
+
})
|
|
762
714
|
},
|
|
763
715
|
{
|
|
764
716
|
text: isProtein ? "Copy Complement DNA Bps" : "Copy Complement",
|
|
765
717
|
className: "openVeCopyComplement",
|
|
766
|
-
|
|
767
|
-
this.openVeCopyComplement &&
|
|
768
|
-
this.openVeCopyComplement.destroy();
|
|
769
|
-
},
|
|
770
|
-
didMount: ({ className }) => {
|
|
771
|
-
this.openVeCopyComplement = makeTextCopyable(
|
|
772
|
-
getComplementSequenceAndAnnotations,
|
|
773
|
-
className
|
|
774
|
-
);
|
|
775
|
-
}
|
|
718
|
+
onClick: makeTextCopyable(getComplementSequenceAndAnnotations)
|
|
776
719
|
},
|
|
777
720
|
copyOptionsMenu
|
|
778
721
|
]
|