@teselagen/ove 0.0.14 → 0.0.15

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.
Files changed (362) hide show
  1. package/index.umd.js +164777 -135861
  2. package/package.json +78 -2
  3. package/src/AlignmentTool/index.js +16 -0
  4. package/src/AlignmentView/AlignmentVisibilityTool.js +105 -0
  5. package/src/AlignmentView/EditTrackNameDialog.js +34 -0
  6. package/src/AlignmentView/HorizontalPanelDragHandle.js +35 -0
  7. package/src/AlignmentView/Minimap.js +520 -0
  8. package/src/AlignmentView/Mismatches.js +134 -0
  9. package/src/AlignmentView/PairwiseAlignmentView.js +68 -0
  10. package/src/AlignmentView/PerformantSelectionLayer.js +32 -0
  11. package/src/AlignmentView/coerceInitialValue.js +7 -0
  12. package/src/AlignmentView/getGapMap.js +12 -0
  13. package/src/AlignmentView/getGaps.js +27 -0
  14. package/src/AlignmentView/getPairwiseOverviewLinearViewOptions.js +38 -0
  15. package/src/AlignmentView/getTrackFromEvent.js +25 -0
  16. package/src/AlignmentView/index.js +2058 -0
  17. package/src/AlignmentView/isTargetWithinEl.js +6 -0
  18. package/src/AlignmentView/style.css +100 -0
  19. package/src/AlignmentView/updateTrackHelper.js +58 -0
  20. package/src/AutoAnnotate.js +500 -0
  21. package/src/AutoAnnotateBpMatchingDialog.js +208 -0
  22. package/src/CircularView/Axis.js +40 -0
  23. package/src/CircularView/AxisNumbers.js +35 -0
  24. package/src/CircularView/Caret.js +63 -0
  25. package/src/CircularView/CircularDnaSequence.js +73 -0
  26. package/src/CircularView/CircularZoomMinimap.js +16 -0
  27. package/src/CircularView/Cutsite.js +18 -0
  28. package/src/CircularView/Cutsites.js +113 -0
  29. package/src/CircularView/DeletionLayer.js +28 -0
  30. package/src/CircularView/Feature.js +83 -0
  31. package/src/CircularView/Labels/index.js +536 -0
  32. package/src/CircularView/Labels/relaxLabelAngles.js +157 -0
  33. package/src/CircularView/Labels/relaxLabels_DEPRECATED.js +105 -0
  34. package/src/CircularView/Labels/style.css +55 -0
  35. package/src/CircularView/Orf.js +25 -0
  36. package/src/CircularView/Part.js +34 -0
  37. package/src/CircularView/PositionAnnotationOnCircle.js +26 -0
  38. package/src/CircularView/Primer.js +41 -0
  39. package/src/CircularView/RotateCircularViewSlider.js +82 -0
  40. package/src/CircularView/SelectionLayer.js +132 -0
  41. package/src/CircularView/VeTopRightContainer.js +12 -0
  42. package/src/CircularView/ZoomCircularViewSlider.js +62 -0
  43. package/src/CircularView/drawAnnotations.js +433 -0
  44. package/src/CircularView/drawDirectedPiePiece.js +142 -0
  45. package/src/CircularView/getAngleForPositionMidpoint.js +3 -0
  46. package/src/CircularView/getInternalLabel.js +40 -0
  47. package/src/CircularView/getRangeAnglesSpecial.js +12 -0
  48. package/src/CircularView/getYOffset.js +15 -0
  49. package/src/CircularView/index.d.ts +20 -0
  50. package/src/CircularView/index.js +930 -0
  51. package/src/CircularView/normalizeAngle.js +3 -0
  52. package/src/CircularView/normalizeAngleRange.js +9 -0
  53. package/src/CircularView/positionCutsites.js +6 -0
  54. package/src/CircularView/shouldFlipText.js +4 -0
  55. package/src/CircularView/style.css +47 -0
  56. package/src/CircularView/utils/polarToSpecialCartesian.js +7 -0
  57. package/src/CreateAnnotationsPage.js +96 -0
  58. package/src/CreateCustomEnzyme/index.js +337 -0
  59. package/src/CreateCustomEnzyme/style.css +100 -0
  60. package/src/CutsiteFilter/AdditionalCutsiteInfoDialog.js +599 -0
  61. package/src/CutsiteFilter/index.js +408 -0
  62. package/src/CutsiteFilter/style.css +23 -0
  63. package/src/CutsiteFilter/withRestrictionEnzymes.js +15 -0
  64. package/src/DigestTool/AddLaddersDialog.js +82 -0
  65. package/src/DigestTool/DigestTool.js +223 -0
  66. package/src/DigestTool/Ladder.css +20 -0
  67. package/src/DigestTool/Ladder.js +303 -0
  68. package/src/DigestTool/createFragmentLines.js +120 -0
  69. package/src/DigestTool/ladderDefaults.js +26 -0
  70. package/src/DigestTool/ruler.css +89 -0
  71. package/src/Editor/CommandHotkeyHandler.js +44 -0
  72. package/src/Editor/DropHandler.css +21 -0
  73. package/src/Editor/DropHandler.js +64 -0
  74. package/src/Editor/FillWindow.js +46 -0
  75. package/src/Editor/darkmode.css +98 -0
  76. package/src/Editor/index.js +1005 -0
  77. package/src/Editor/style.css +235 -0
  78. package/src/Editor/userDefinedHandlersAndOpts.js +56 -0
  79. package/src/EnzymeViewer/index.js +81 -0
  80. package/src/EnzymeViewer/style.css +6 -0
  81. package/src/FindBar/index.js +411 -0
  82. package/src/FindBar/style.css +46 -0
  83. package/src/GlobalDialog.js +66 -0
  84. package/src/GlobalDialogUtils.js +85 -0
  85. package/src/LinearView/SequenceName.js +15 -0
  86. package/src/LinearView/ZoomLinearView.js +47 -0
  87. package/src/LinearView/index.js +374 -0
  88. package/src/LinearView/style.css +12 -0
  89. package/src/ManageEnzymes/index.js +326 -0
  90. package/src/ManageEnzymes/style.css +100 -0
  91. package/src/MenuBar/defaultConfig.js +149 -0
  92. package/src/MenuBar/index.js +98 -0
  93. package/src/MenuBar/viewSubmenu.js +479 -0
  94. package/src/PCRTool/PCRTool.js +173 -0
  95. package/src/Reflex/Browser.js +107 -0
  96. package/src/Reflex/ReflexContainer.js +802 -0
  97. package/src/Reflex/ReflexElement.js +160 -0
  98. package/src/Reflex/ReflexEvents.js +77 -0
  99. package/src/Reflex/ReflexSplitter.js +205 -0
  100. package/src/Reflex/index.js +5 -0
  101. package/src/Reflex/reflex-styles.css +128 -0
  102. package/src/Reflex/reflex-styles.css.map +9 -0
  103. package/src/RowItem/AnnotationContainerHolder.js +20 -0
  104. package/src/RowItem/AnnotationPositioner.js +27 -0
  105. package/src/RowItem/Axis.js +149 -0
  106. package/src/RowItem/Caret/index.js +64 -0
  107. package/src/RowItem/Caret/style.css +8 -0
  108. package/src/RowItem/Chromatograms/Chromatogram.js +289 -0
  109. package/src/RowItem/CutsiteSelectionLayers.js +47 -0
  110. package/src/RowItem/Cutsites.js +271 -0
  111. package/src/RowItem/DeletionLayers/index.js +113 -0
  112. package/src/RowItem/DeletionLayers/style.css +5 -0
  113. package/src/RowItem/Labels.js +327 -0
  114. package/src/RowItem/Orf.js +109 -0
  115. package/src/RowItem/Orfs.js +35 -0
  116. package/src/RowItem/ReplacementLayers/style.css +5 -0
  117. package/src/RowItem/SelectionLayer/index.js +184 -0
  118. package/src/RowItem/SelectionLayer/style.css +21 -0
  119. package/src/RowItem/Sequence.js +269 -0
  120. package/src/RowItem/StackedAnnotations/PointedAnnotation.js +347 -0
  121. package/src/RowItem/StackedAnnotations/getStructuredBases.js +97 -0
  122. package/src/RowItem/StackedAnnotations/index.js +182 -0
  123. package/src/RowItem/StackedAnnotations/primerBases.js +218 -0
  124. package/src/RowItem/StackedAnnotations/style.css +14 -0
  125. package/src/RowItem/Translations/AASliver.js +190 -0
  126. package/src/RowItem/Translations/Translation.js +162 -0
  127. package/src/RowItem/Translations/index.js +54 -0
  128. package/src/RowItem/Translations/style.css +3 -0
  129. package/src/RowItem/constants.js +3 -0
  130. package/src/RowItem/getCutsiteLabelHeights.js +56 -0
  131. package/src/RowItem/getXStartAndWidthFromNonCircularRange.js +12 -0
  132. package/src/RowItem/getXStartAndWidthOfRangeWrtRow.js +27 -0
  133. package/src/RowItem/getXStartAndWidthOfRowAnnotation.js +19 -0
  134. package/src/RowItem/index.js +647 -0
  135. package/src/RowItem/partOverhangs.js +6 -0
  136. package/src/RowItem/style.css +103 -0
  137. package/src/RowItem/utils.js +32 -0
  138. package/src/RowView/estimateRowHeight.js +184 -0
  139. package/src/RowView/index.d.ts +10 -0
  140. package/src/RowView/index.js +554 -0
  141. package/src/RowView/style.css +12 -0
  142. package/src/SimpleCircularOrLinearView.js +379 -0
  143. package/src/SimpleOligoPreview.js +39 -0
  144. package/src/StatusBar/MeltingTemp.js +81 -0
  145. package/src/StatusBar/index.js +275 -0
  146. package/src/StatusBar/style.css +38 -0
  147. package/src/ToolBar/ToolbarItem.js +194 -0
  148. package/src/ToolBar/alignmentTool.js +503 -0
  149. package/src/ToolBar/array_move.js +10 -0
  150. package/src/ToolBar/cutsiteTool.js +88 -0
  151. package/src/ToolBar/downloadTool.js +38 -0
  152. package/src/ToolBar/editTool.js +26 -0
  153. package/src/ToolBar/featureTool.js +34 -0
  154. package/src/ToolBar/findTool.js +2 -0
  155. package/src/ToolBar/importTool.js +27 -0
  156. package/src/ToolBar/index.js +231 -0
  157. package/src/ToolBar/inlineFindTool.js +38 -0
  158. package/src/ToolBar/oligoTool.js +30 -0
  159. package/src/ToolBar/orfTool.js +141 -0
  160. package/src/ToolBar/partTool.js +47 -0
  161. package/src/ToolBar/printTool.js +31 -0
  162. package/src/ToolBar/redoTool.js +30 -0
  163. package/src/ToolBar/saveTool.js +48 -0
  164. package/src/ToolBar/style.css +138 -0
  165. package/src/ToolBar/undoTool.js +30 -0
  166. package/src/ToolBar/veToolbarIcons/find.png +0 -0
  167. package/src/ToolBar/veToolbarIcons/fullscreen.png +0 -0
  168. package/src/ToolBar/veToolbarIcons/linear.png +0 -0
  169. package/src/ToolBar/veToolbarIcons/pie.png +0 -0
  170. package/src/ToolBar/veToolbarIcons/print.png +0 -0
  171. package/src/ToolBar/veToolbarIcons/save.png +0 -0
  172. package/src/ToolBar/veToolbarIcons/show_cut_sites.png +0 -0
  173. package/src/ToolBar/veToolbarIcons/show_features.png +0 -0
  174. package/src/ToolBar/veToolbarIcons/show_orfs.png +0 -0
  175. package/src/ToolBar/veToolbarIcons/show_primers.png +0 -0
  176. package/src/ToolBar/veToolbarIcons/toggle_views.svg +1 -0
  177. package/src/ToolBar/versionHistoryTool.js +20 -0
  178. package/src/ToolBar/visibilityTool.js +39 -0
  179. package/src/VersionHistoryView/index.js +215 -0
  180. package/src/addAlignment.js +6 -0
  181. package/src/commands/getOveHotkeyDefs.js +12 -0
  182. package/src/commands/index.js +1585 -0
  183. package/src/constants/constants.js +2 -0
  184. package/src/constants/dnaToColor.js +17 -0
  185. package/src/constants/draggableClassnames.js +5 -0
  186. package/src/constants/findToolConstants.js +1 -0
  187. package/src/constants/orfFrameToColorMap.js +10 -0
  188. package/src/constants/rowviewContants.js +3 -0
  189. package/src/constants/specialCutsiteFilterOptions.js +22 -0
  190. package/src/constants.js +1 -0
  191. package/src/createVectorEditor/index.js +138 -0
  192. package/src/createVectorEditor/makeStore.js +34 -0
  193. package/src/fileUtils.js +103 -0
  194. package/src/helperComponents/AddOrEditAnnotationDialog/index.js +711 -0
  195. package/src/helperComponents/AddOrEditAnnotationDialog/style.css +11 -0
  196. package/src/helperComponents/AddOrEditFeatureDialog/index.js +58 -0
  197. package/src/helperComponents/AddOrEditPartDialog/index.js +101 -0
  198. package/src/helperComponents/AddOrEditPrimerDialog/EditCaretPosition.js +234 -0
  199. package/src/helperComponents/AddOrEditPrimerDialog/index.js +329 -0
  200. package/src/helperComponents/AddOrEditPrimerDialog/style.css +41 -0
  201. package/src/helperComponents/EnzymesDialog/index.js +904 -0
  202. package/src/helperComponents/EnzymesDialog/style.css +21 -0
  203. package/src/helperComponents/GoToDialog.js +21 -0
  204. package/src/helperComponents/MergeFeaturesDialog/index.js +253 -0
  205. package/src/helperComponents/MergeFeaturesDialog/style.css +3 -0
  206. package/src/helperComponents/MultipleSeqsDetectedOnImportDialog.js +74 -0
  207. package/src/helperComponents/PinchHelper/PinchHelper.js +24 -0
  208. package/src/helperComponents/PrintDialog/index.js +396 -0
  209. package/src/helperComponents/PrintDialog/style.css +4 -0
  210. package/src/helperComponents/PropertiesDialog/ColorPicker.js +30 -0
  211. package/src/helperComponents/PropertiesDialog/CutsiteProperties.js +185 -0
  212. package/src/helperComponents/PropertiesDialog/FeatureProperties.js +6 -0
  213. package/src/helperComponents/PropertiesDialog/GenbankView.js +74 -0
  214. package/src/helperComponents/PropertiesDialog/GeneralProperties.js +140 -0
  215. package/src/helperComponents/PropertiesDialog/GenericAnnotationProperties.js +406 -0
  216. package/src/helperComponents/PropertiesDialog/OrfProperties.js +117 -0
  217. package/src/helperComponents/PropertiesDialog/PartProperties.js +9 -0
  218. package/src/helperComponents/PropertiesDialog/PrimerProperties.js +19 -0
  219. package/src/helperComponents/PropertiesDialog/SingleEnzymeCutsiteInfo.js +131 -0
  220. package/src/helperComponents/PropertiesDialog/TranslationProperties.js +149 -0
  221. package/src/helperComponents/PropertiesDialog/index.js +166 -0
  222. package/src/helperComponents/PropertiesDialog/style.css +68 -0
  223. package/src/helperComponents/PropertiesDialog/typeField.js +24 -0
  224. package/src/helperComponents/PropertiesDialog/utils.js +37 -0
  225. package/src/helperComponents/RemoveDuplicates/index.js +194 -0
  226. package/src/helperComponents/RenameSequenceDialog.js +7 -0
  227. package/src/helperComponents/SelectDialog.js +150 -0
  228. package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.css +5 -0
  229. package/src/helperComponents/UncontrolledSliderWithPlusMinusBtns.js +134 -0
  230. package/src/helperComponents/VeWarning/index.js +22 -0
  231. package/src/helperComponents/VeWarning/style.css +10 -0
  232. package/src/helperComponents/createSimpleDialog.js +89 -0
  233. package/src/helperComponents/partTagSearch.js +72 -0
  234. package/src/helperComponents/simpleDialog.css +13 -0
  235. package/src/helperComponents/withHover.js +90 -0
  236. package/src/index.js +60 -0
  237. package/src/redux/alignments.js +373 -0
  238. package/src/redux/annotationLabelVisibility.js +53 -0
  239. package/src/redux/annotationVisibility.js +196 -0
  240. package/src/redux/annotationsToSupport.js +104 -0
  241. package/src/redux/caretPosition.js +27 -0
  242. package/src/redux/charWidth.js +22 -0
  243. package/src/redux/copyOptions.js +34 -0
  244. package/src/redux/createYourOwnEnzyme.js +39 -0
  245. package/src/redux/deletionLayers.js +36 -0
  246. package/src/redux/digestTool.js +34 -0
  247. package/src/redux/featureLengthsToHide.js +27 -0
  248. package/src/redux/findTool.js +79 -0
  249. package/src/redux/frameTranslations.js +52 -0
  250. package/src/redux/hoveredAnnotation.js +24 -0
  251. package/src/redux/index.js +196 -0
  252. package/src/redux/labelLineIntensity.js +25 -0
  253. package/src/redux/labelSize.js +23 -0
  254. package/src/redux/lastSavedId.js +20 -0
  255. package/src/redux/middleware.js +112 -0
  256. package/src/redux/minimumOrfSize.js +24 -0
  257. package/src/redux/modalActions.js +3 -0
  258. package/src/redux/panelsShown.js +273 -0
  259. package/src/redux/partLengthsToHide.js +23 -0
  260. package/src/redux/primerLengthsToHide.js +27 -0
  261. package/src/redux/propertiesTool.js +40 -0
  262. package/src/redux/readOnly.js +28 -0
  263. package/src/redux/replacementLayers.js +36 -0
  264. package/src/redux/restrictionEnzymes.js +52 -0
  265. package/src/redux/selectedAnnotations.js +89 -0
  266. package/src/redux/selectedPartTags.js +21 -0
  267. package/src/redux/selectionLayer.js +46 -0
  268. package/src/redux/sequenceData/circular.js +19 -0
  269. package/src/redux/sequenceData/description.js +21 -0
  270. package/src/redux/sequenceData/features.js +19 -0
  271. package/src/redux/sequenceData/index.js +81 -0
  272. package/src/redux/sequenceData/lineageLines.js +11 -0
  273. package/src/redux/sequenceData/materiallyAvailable.js +19 -0
  274. package/src/redux/sequenceData/name.js +19 -0
  275. package/src/redux/sequenceData/parts.js +19 -0
  276. package/src/redux/sequenceData/primers.js +19 -0
  277. package/src/redux/sequenceData/sequence.js +12 -0
  278. package/src/redux/sequenceData/sharedActionCreators.js +0 -0
  279. package/src/redux/sequenceData/translations.js +20 -0
  280. package/src/redux/sequenceData/upsertDeleteActionGenerator.js +31 -0
  281. package/src/redux/sequenceDataHistory.js +43 -0
  282. package/src/redux/showGCContent.js +23 -0
  283. package/src/redux/toolBar.js +25 -0
  284. package/src/redux/uppercaseSequenceMapFont.js +25 -0
  285. package/src/redux/useAdditionalOrfStartCodons.js +24 -0
  286. package/src/redux/utils/addDashesForMatchStartAndEndForTracks/index.js +71 -0
  287. package/src/redux/utils/addMetaToActionCreators.js +12 -0
  288. package/src/redux/utils/createMergedDefaultStateReducer.js +30 -0
  289. package/src/redux/utils/createMetaAction.js +12 -0
  290. package/src/redux/versionHistory.js +27 -0
  291. package/src/selectors/annotationLabelVisibility.js +2 -0
  292. package/src/selectors/annotationSearchSelector.js +24 -0
  293. package/src/selectors/cdsFeaturesSelector.js +9 -0
  294. package/src/selectors/circularSelector.js +4 -0
  295. package/src/selectors/cutsiteLabelColorSelector.js +6 -0
  296. package/src/selectors/cutsitesByRangeSelector.js +5 -0
  297. package/src/selectors/cutsitesSelector.js +61 -0
  298. package/src/selectors/editorSelector.js +2 -0
  299. package/src/selectors/featuresSelector.js +8 -0
  300. package/src/selectors/filteredCutsitesSelector.js +137 -0
  301. package/src/selectors/filteredFeaturesSelector.js +32 -0
  302. package/src/selectors/filteredPartsSelector.js +57 -0
  303. package/src/selectors/filteredPrimersSelector.js +27 -0
  304. package/src/selectors/filteredRestrictionEnzymesSelector.js +1 -0
  305. package/src/selectors/getAdditionalEnzymesSelector.js +46 -0
  306. package/src/selectors/index.js +41 -0
  307. package/src/selectors/isEnzymeFilterAndSelector.js +1 -0
  308. package/src/selectors/minimumOrfSizeSelector.js +2 -0
  309. package/src/selectors/orfsSelector.js +15 -0
  310. package/src/selectors/partsSelector.js +8 -0
  311. package/src/selectors/primersSelector.js +8 -0
  312. package/src/selectors/restrictionEnzymesSelector.js +34 -0
  313. package/src/selectors/searchLayersSelector.js +71 -0
  314. package/src/selectors/selectedAnnotationsSelector.js +1 -0
  315. package/src/selectors/selectedCutsitesSelector.js +21 -0
  316. package/src/selectors/sequenceDataSelector.js +2 -0
  317. package/src/selectors/sequenceLengthSelector.js +5 -0
  318. package/src/selectors/sequenceSelector.js +4 -0
  319. package/src/selectors/tagsToBoldSelector.js +2 -0
  320. package/src/selectors/translationSearchMatchesSelector.js +14 -0
  321. package/src/selectors/translationsRawSelector.js +8 -0
  322. package/src/selectors/translationsSelector.js +137 -0
  323. package/src/style.css +82 -0
  324. package/src/updateEditor.js +198 -0
  325. package/src/utils/PassThrough.js +3 -0
  326. package/src/utils/addWrappedAddons.js +20 -0
  327. package/src/utils/annotationTypes.js +37 -0
  328. package/src/utils/arrayUtils.js +19 -0
  329. package/src/utils/calculateTickMarkPositionsForGivenRange.js +47 -0
  330. package/src/utils/cleanSequenceData_DEPRECATED/arrayToObjWithIds.js +17 -0
  331. package/src/utils/combineReducersDontIgnoreKeys.js +12 -0
  332. package/src/utils/commandUtils.js +18 -0
  333. package/src/utils/editorUtils.js +223 -0
  334. package/src/utils/getAnnotationClassnames.js +12 -0
  335. package/src/utils/getAnnotationNameAndStartStopString.js +61 -0
  336. package/src/utils/getVisibleStartEnd.js +7 -0
  337. package/src/utils/massageTickSpacing.js +19 -0
  338. package/src/utils/onlyUpdateForKeysDeep.js +31 -0
  339. package/src/utils/prepareRowData.js +64 -0
  340. package/src/utils/proteinUtils.js +3 -0
  341. package/src/utils/pureNoFunc.js +18 -0
  342. package/src/utils/selectionLayer.js +25 -0
  343. package/src/utils/shouldRerender.js +27 -0
  344. package/src/utils/showFileDialog.js +26 -0
  345. package/src/utils/updateLabelsForInViewFeatures.js +55 -0
  346. package/src/utils/updateLabelsForInViewFeaturesCircView.js +41 -0
  347. package/src/utils/useAAColorType.js +8 -0
  348. package/src/utils/useAnnotationLimits.js +42 -0
  349. package/src/utils/useChromatogramPrefs.js +31 -0
  350. package/src/utils/useLadders.js +6 -0
  351. package/src/utils/useMeltingTemp.js +7 -0
  352. package/src/utils/useTmType.js +10 -0
  353. package/src/withEditorInteractions/Keyboard.js +86 -0
  354. package/src/withEditorInteractions/clickAndDragUtils.js +576 -0
  355. package/src/withEditorInteractions/createSequenceInputPopup.js +296 -0
  356. package/src/withEditorInteractions/createSequenceInputPopupStyle.css +85 -0
  357. package/src/withEditorInteractions/getBpsPerRow.js +19 -0
  358. package/src/withEditorInteractions/index.js +1252 -0
  359. package/src/withEditorInteractions/isElementInViewport.js +29 -0
  360. package/src/withEditorInteractions/moveCaret.js +58 -0
  361. package/src/withEditorProps/index.js +1010 -0
  362. package/index.mjs +0 -193228
@@ -0,0 +1,1010 @@
1
+ import { getFeatureToColorMap } from "@teselagen/sequence-utils";
2
+ import {
3
+ anyToJson,
4
+ jsonToGenbank,
5
+ jsonToFasta,
6
+ cleanUpTeselagenJsonForExport
7
+ } from "@teselagen/bio-parsers";
8
+ import FileSaver from "file-saver";
9
+
10
+ import { bindActionCreators } from "redux";
11
+ import { connect } from "react-redux";
12
+ import { compose, withHandlers, withProps } from "recompose";
13
+ import { getFormValues /* formValueSelector */ } from "redux-form";
14
+ import { showConfirmationDialog } from "@teselagen/ui";
15
+ import { some, map, keyBy, omit, isArray, noop } from "lodash";
16
+ import {
17
+ tidyUpSequenceData,
18
+ getComplementSequenceAndAnnotations,
19
+ insertSequenceDataAtPositionOrRange,
20
+ getReverseComplementSequenceAndAnnotations,
21
+ rotateSequenceDataToPosition
22
+ } from "@teselagen/sequence-utils";
23
+ import { Intent } from "@blueprintjs/core";
24
+ import {
25
+ convertRangeTo0Based,
26
+ getRangeLength,
27
+ invertRange,
28
+ normalizeRange
29
+ } from "@teselagen/range-utils";
30
+ import shortid from "shortid";
31
+
32
+ import addMetaToActionCreators from "../redux/utils/addMetaToActionCreators";
33
+ import { actions, editorReducer } from "../redux";
34
+ import s from "../selectors";
35
+ import { allTypes } from "../utils/annotationTypes";
36
+
37
+ import { MAX_MATCHES_DISPLAYED } from "../constants/findToolConstants";
38
+ import { createSelector, defaultMemoize } from "reselect";
39
+ import domtoimage from "dom-to-image";
40
+ import {
41
+ hideDialog,
42
+ showAddOrEditAnnotationDialog,
43
+ showDialog
44
+ } from "../GlobalDialogUtils";
45
+ import updateEditor from "../updateEditor";
46
+ // import { getStartEndFromBases } from "../utils/editorUtils";
47
+
48
+ const getUpperOrLowerSeq = defaultMemoize(
49
+ (uppercaseSequenceMapFont, sequence = "") =>
50
+ uppercaseSequenceMapFont === "uppercase"
51
+ ? sequence.toUpperCase()
52
+ : uppercaseSequenceMapFont === "lowercase"
53
+ ? sequence.toLowerCase()
54
+ : sequence
55
+ );
56
+
57
+ const getTypesToOmit = (annotationsToSupport) => {
58
+ const typesToOmit = {};
59
+ allTypes.forEach((type) => {
60
+ if (!annotationsToSupport[type]) typesToOmit[type] = false;
61
+ });
62
+ return typesToOmit;
63
+ };
64
+
65
+ const getVisibilities = createSelector(
66
+ (ed) => ed.annotationVisibility,
67
+ (ed) => ed.annotationLabelVisibility,
68
+ (ed) => ed.annotationsToSupport,
69
+ (annotationVisibility, annotationLabelVisibility, annotationsToSupport) => {
70
+ const typesToOmit = getTypesToOmit(annotationsToSupport);
71
+ const annotationVisibilityToUse = {
72
+ ...annotationVisibility,
73
+ ...typesToOmit
74
+ };
75
+ const annotationLabelVisibilityToUse = {
76
+ ...annotationLabelVisibility,
77
+ ...typesToOmit
78
+ };
79
+ return {
80
+ annotationVisibilityToUse,
81
+ annotationLabelVisibilityToUse,
82
+ typesToOmit
83
+ };
84
+ }
85
+ );
86
+
87
+ async function getSaveDialogEl() {
88
+ return new Promise((resolve) => {
89
+ showDialog({
90
+ dialogType: "PrintDialog",
91
+ props: {
92
+ dialogProps: {
93
+ title: "Generating Image to Save...",
94
+ isCloseButtonShown: false
95
+ },
96
+ addPaddingBottom: true,
97
+ hideLinearCircularToggle: true,
98
+ hidePrintButton: true
99
+ }
100
+ });
101
+
102
+ const id = setInterval(() => {
103
+ const componentToPrint = document.querySelector(".bp3-dialog");
104
+ if (componentToPrint) {
105
+ clearInterval(id);
106
+ resolve(componentToPrint);
107
+ }
108
+ }, 1000);
109
+ });
110
+ }
111
+ /**
112
+ * Function to generate a png
113
+ *
114
+ * @return {object} - Blob (png) | Error
115
+ */
116
+ const generatePngFromPrintDialog = async (props) => {
117
+ const saveDialog = await getSaveDialogEl(props);
118
+
119
+ const printArea = saveDialog.querySelector(".bp3-dialog-body");
120
+
121
+ const result = await domtoimage
122
+ .toBlob(printArea)
123
+ .then((blob) => {
124
+ return blob;
125
+ })
126
+ .catch((error) => {
127
+ console.error(error);
128
+ return error;
129
+ });
130
+ hideDialog();
131
+ return result;
132
+ };
133
+
134
+ export const handleSave =
135
+ (props) =>
136
+ async (opts = {}) => {
137
+ const {
138
+ onSave,
139
+ onSaveAs,
140
+ generatePng,
141
+ readOnly,
142
+ alwaysAllowSave,
143
+ sequenceData,
144
+ lastSavedIdUpdate
145
+ } = props;
146
+ const saveHandler = opts.isSaveAs ? onSaveAs || onSave : onSave;
147
+
148
+ const updateLastSavedIdToCurrent = () => {
149
+ lastSavedIdUpdate(sequenceData.stateTrackingId);
150
+ };
151
+
152
+ // Optionally generate png
153
+ if (generatePng) {
154
+ opts.pngFile = await generatePngFromPrintDialog(props);
155
+ }
156
+
157
+ // TODO: pass additionalProps (blob or error) to the user
158
+ const promiseOrVal =
159
+ (!readOnly || alwaysAllowSave || opts.isSaveAs) &&
160
+ saveHandler &&
161
+ saveHandler(
162
+ opts,
163
+ tidyUpSequenceData(sequenceData, { annotationsAsObjects: true }),
164
+ props,
165
+ updateLastSavedIdToCurrent
166
+ );
167
+
168
+ if (promiseOrVal && promiseOrVal.then) {
169
+ return promiseOrVal.then(updateLastSavedIdToCurrent);
170
+ }
171
+ };
172
+
173
+ export const handleInverse = (props) => () => {
174
+ const {
175
+ sequenceLength,
176
+ selectionLayer,
177
+ caretPosition,
178
+ selectionLayerUpdate,
179
+ caretPositionUpdate
180
+ } = props;
181
+
182
+ if (sequenceLength <= 0) {
183
+ return false;
184
+ }
185
+ if (selectionLayer.start > -1) {
186
+ if (getRangeLength(selectionLayer, sequenceLength) === sequenceLength) {
187
+ caretPositionUpdate(selectionLayer.start);
188
+ } else {
189
+ selectionLayerUpdate(invertRange(selectionLayer, sequenceLength));
190
+ }
191
+ } else {
192
+ if (caretPosition > -1) {
193
+ selectionLayerUpdate(
194
+ normalizeRange(
195
+ {
196
+ start: caretPosition,
197
+ end: caretPosition - 1
198
+ },
199
+ sequenceLength
200
+ )
201
+ );
202
+ } else {
203
+ selectionLayerUpdate({
204
+ start: 0,
205
+ end: sequenceLength - 1
206
+ });
207
+ }
208
+ }
209
+ };
210
+
211
+ export const updateCircular = (props) => async (isCircular) => {
212
+ const { _updateCircular, updateSequenceData, sequenceData } = props;
213
+ if (!isCircular && hasAnnotationThatSpansOrigin(sequenceData)) {
214
+ const doAction = await showConfirmationDialog({
215
+ intent: Intent.DANGER, //applied to the right most confirm button
216
+ confirmButtonText: "Truncate Annotations",
217
+ canEscapeKeyCancel: true, //this is false by default
218
+ text: "Careful! Origin spanning annotations will be truncated. Are you sure you want to make the sequence linear?"
219
+ });
220
+ if (!doAction) return; //stop early
221
+ updateSequenceData(truncateOriginSpanningAnnotations(sequenceData), {
222
+ batchUndoStart: true
223
+ });
224
+ }
225
+ _updateCircular(isCircular, { batchUndoEnd: true });
226
+ };
227
+
228
+ export const importSequenceFromFile =
229
+ (props) =>
230
+ async (file, opts = {}) => {
231
+ const { onImport } = props;
232
+ const result = await anyToJson(file, { acceptParts: true, ...opts });
233
+ // TODO maybe handle import errors/warnings better
234
+ const failed = !result[0].success;
235
+ const messages = result[0].messages;
236
+ if (isArray(messages)) {
237
+ messages.forEach((msg) => {
238
+ const type = msg.substr(0, 20).toLowerCase().includes("error")
239
+ ? failed
240
+ ? "error"
241
+ : "warning"
242
+ : "info";
243
+ window.toastr[type](msg);
244
+ });
245
+ }
246
+ if (failed) {
247
+ window.toastr.error(
248
+ "Error importing sequence(s). See console for more errors"
249
+ );
250
+ console.error(`Seq import results:`, result);
251
+ } else if (result.length > 1) {
252
+ showDialog({
253
+ dialogType: "MultipleSeqsDetectedOnImportDialog",
254
+ props: {
255
+ finishDisplayingSeq,
256
+ results: result
257
+ }
258
+ });
259
+ } else {
260
+ finishDisplayingSeq(result[0].parsedSequence);
261
+ }
262
+ async function finishDisplayingSeq(seqData) {
263
+ if (onImport) {
264
+ seqData = await onImport(seqData);
265
+ }
266
+
267
+ if (seqData) {
268
+ seqData.stateTrackingId = shortid();
269
+ updateEditor(
270
+ {
271
+ getState: () => ({ VectorEditor: { [props.editorName]: props } }),
272
+ dispatch: props.dispatch
273
+ },
274
+ props.editorName,
275
+ { sequenceData: seqData }
276
+ );
277
+ props.flipActiveTabFromLinearOrCircularIfNecessary(seqData.circular);
278
+
279
+ window.toastr.success("Sequence Imported");
280
+ }
281
+ }
282
+ };
283
+
284
+ export const exportSequenceToFile = (props) => (format) => {
285
+ const { sequenceData } = props;
286
+ let convert, fileExt;
287
+
288
+ if (format === "genbank") {
289
+ convert = jsonToGenbank;
290
+ fileExt = "gb";
291
+ } else if (format === "genpept") {
292
+ convert = jsonToGenbank;
293
+ fileExt = "gp";
294
+ } else if (format === "teselagenJson") {
295
+ convert = jsonToJson;
296
+ fileExt = "json";
297
+ } else if (format === "fasta") {
298
+ convert = jsonToFasta;
299
+ fileExt = "fasta";
300
+ } else {
301
+ console.error(`Invalid export format: '${format}'`); // dev error
302
+ return;
303
+ }
304
+ const blob = new Blob([convert(sequenceData)], { type: "text/plain" });
305
+ const filename = `${sequenceData.name || "Untitled_Sequence"}.${fileExt}`;
306
+ FileSaver.saveAs(blob, filename);
307
+ window.toastr.success("File Downloaded Successfully");
308
+ };
309
+
310
+ /**
311
+ * This function basically connects the wrapped component with all of the state stored in a given editor instance
312
+ * and then some extra goodies like computed properties and namespace bound action handlers
313
+ */
314
+ export default compose(
315
+ connect(
316
+ mapStateToProps,
317
+ mapDispatchToActions,
318
+ (mapProps, dispatchProps, ownProps) => {
319
+ const toSpread = {};
320
+ if (mapProps.annotationToAdd) {
321
+ toSpread.original_selectionLayerUpdate =
322
+ dispatchProps.selectionLayerUpdate;
323
+ toSpread.selectionLayerUpdate = (sel) => {
324
+ dispatchProps.dispatch({
325
+ type: "@@redux-form/CHANGE",
326
+ meta: {
327
+ form: mapProps.annotationToAdd.formName,
328
+ field: "start",
329
+ touch: false,
330
+ persistentSubmitErrors: false
331
+ },
332
+ payload: sel.start + 1
333
+ });
334
+ dispatchProps.dispatch({
335
+ type: "@@redux-form/CHANGE",
336
+ meta: {
337
+ form: mapProps.annotationToAdd.formName,
338
+ field: "end",
339
+ touch: false,
340
+ persistentSubmitErrors: false
341
+ },
342
+ payload: sel.end + 1
343
+ });
344
+ };
345
+ toSpread.caretPositionUpdate = noop;
346
+ }
347
+ return { ...ownProps, ...mapProps, ...dispatchProps, ...toSpread };
348
+ }
349
+ ),
350
+ withHandlers({
351
+ wrappedInsertSequenceDataAtPositionOrRange: (props) => {
352
+ return (
353
+ _sequenceDataToInsert,
354
+ _existingSequenceData,
355
+ _caretPositionOrRange,
356
+ _options
357
+ ) => {
358
+ const {
359
+ sequenceDataToInsert,
360
+ existingSequenceData,
361
+ caretPositionOrRange,
362
+ options
363
+ } = props.beforeSequenceInsertOrDelete
364
+ ? props.beforeSequenceInsertOrDelete(
365
+ tidyUpSequenceData(_sequenceDataToInsert),
366
+ tidyUpSequenceData(_existingSequenceData),
367
+ _caretPositionOrRange,
368
+ _options
369
+ ) || {}
370
+ : {};
371
+ return [
372
+ insertSequenceDataAtPositionOrRange(
373
+ sequenceDataToInsert || _sequenceDataToInsert,
374
+ existingSequenceData || _existingSequenceData,
375
+ caretPositionOrRange || _caretPositionOrRange,
376
+ options || _options
377
+ ),
378
+ options || _options || {}
379
+ ];
380
+ };
381
+ },
382
+
383
+ upsertTranslation: (props) => {
384
+ return async (translationToUpsert) => {
385
+ if (!translationToUpsert) return;
386
+ const { _upsertTranslation, sequenceData } = props;
387
+ if (
388
+ !translationToUpsert.id &&
389
+ some(sequenceData.translations || [], (existingTranslation) => {
390
+ if (
391
+ //check if an identical existingTranslation exists already
392
+ existingTranslation.translationType === "User Created" &&
393
+ existingTranslation.start === translationToUpsert.start &&
394
+ existingTranslation.end === translationToUpsert.end &&
395
+ !!translationToUpsert.forward === !!existingTranslation.forward
396
+ ) {
397
+ return true;
398
+ }
399
+ })
400
+ ) {
401
+ const doAction = await showConfirmationDialog({
402
+ // intent: Intent.DANGER, //applied to the right most confirm button
403
+ confirmButtonText: "Create Translation",
404
+ canEscapeKeyCancel: true, //this is false by default
405
+ text: "This region has already been translated. Are you sure you want to make another translation for it?"
406
+ });
407
+ if (!doAction) return; //stop early
408
+ }
409
+ _upsertTranslation(translationToUpsert);
410
+ };
411
+ }
412
+ }),
413
+ withHandlers({
414
+ handleSave,
415
+ importSequenceFromFile,
416
+ exportSequenceToFile,
417
+ updateCircular,
418
+ //add additional "computed handlers here"
419
+ selectAll: (props) => () => {
420
+ const { sequenceLength, selectionLayerUpdate } = props;
421
+ sequenceLength > 0 &&
422
+ selectionLayerUpdate({
423
+ start: 0,
424
+ end: sequenceLength - 1
425
+ });
426
+ },
427
+ //handleNewPrimer handleNewFeature handleNewPart
428
+ ...["Part", "Feature", "Primer"].reduce((acc, key) => {
429
+ acc[`handleNew${key}`] = (props) => () => {
430
+ const { readOnly, selectionLayer, caretPosition, sequenceData } = props;
431
+
432
+ if (readOnly) {
433
+ window.toastr.warning(
434
+ `Sorry, Can't Create New ${key}s in Read-Only Mode`
435
+ );
436
+ } else {
437
+ const rangeToUse =
438
+ selectionLayer.start > -1
439
+ ? { ...selectionLayer, id: undefined }
440
+ : caretPosition > -1
441
+ ? {
442
+ start: caretPosition,
443
+ end: sequenceData.isProtein
444
+ ? caretPosition + 2
445
+ : caretPosition
446
+ }
447
+ : {
448
+ start: 0,
449
+ end: sequenceData.isProtein ? 2 : 0
450
+ };
451
+ showAddOrEditAnnotationDialog({
452
+ type: key.toLowerCase(),
453
+ annotation: {
454
+ ...rangeToUse,
455
+ forward: !(selectionLayer.forward === false)
456
+ }
457
+ });
458
+ }
459
+ };
460
+ return acc;
461
+ }, {}),
462
+
463
+ handleRotateToCaretPosition: (props) => () => {
464
+ const {
465
+ caretPosition,
466
+ readOnly,
467
+ sequenceData,
468
+ updateSequenceData,
469
+ caretPositionUpdate
470
+ } = props;
471
+ if (readOnly) {
472
+ return;
473
+ }
474
+ if (caretPosition < 0) return;
475
+ updateSequenceData(
476
+ rotateSequenceDataToPosition(sequenceData, caretPosition)
477
+ );
478
+ caretPositionUpdate(0);
479
+ },
480
+
481
+ handleReverseComplementSelection: (props) => () => {
482
+ const {
483
+ sequenceData,
484
+ updateSequenceData,
485
+ wrappedInsertSequenceDataAtPositionOrRange,
486
+ selectionLayer
487
+ } = props;
488
+ if (!(selectionLayer.start > -1)) {
489
+ return; //return early
490
+ }
491
+ const reversedSeqData = getReverseComplementSequenceAndAnnotations(
492
+ sequenceData,
493
+ {
494
+ range: selectionLayer
495
+ }
496
+ );
497
+ const [newSeqData] = wrappedInsertSequenceDataAtPositionOrRange(
498
+ reversedSeqData,
499
+ sequenceData,
500
+ selectionLayer,
501
+ {
502
+ maintainOriginSplit: true
503
+ }
504
+ );
505
+ updateSequenceData(newSeqData);
506
+ },
507
+
508
+ handleComplementSelection: (props) => () => {
509
+ const {
510
+ sequenceData,
511
+ updateSequenceData,
512
+ selectionLayer,
513
+ wrappedInsertSequenceDataAtPositionOrRange
514
+ } = props;
515
+ if (!(selectionLayer.start > -1)) {
516
+ return; //return early
517
+ }
518
+ const comp = getComplementSequenceAndAnnotations(sequenceData, {
519
+ range: selectionLayer
520
+ });
521
+ const [newSeqData] = wrappedInsertSequenceDataAtPositionOrRange(
522
+ comp,
523
+ sequenceData,
524
+ selectionLayer,
525
+ {
526
+ maintainOriginSplit: true
527
+ }
528
+ );
529
+ updateSequenceData(newSeqData);
530
+ },
531
+
532
+ handleReverseComplementSequence: (props) => () => {
533
+ const { sequenceData, updateSequenceData } = props;
534
+ updateSequenceData(
535
+ getReverseComplementSequenceAndAnnotations(sequenceData)
536
+ );
537
+ window.toastr.success("Reverse Complemented Sequence Successfully");
538
+ },
539
+
540
+ handleComplementSequence: (props) => () => {
541
+ const { sequenceData, updateSequenceData } = props;
542
+ updateSequenceData(getComplementSequenceAndAnnotations(sequenceData));
543
+ window.toastr.success("Complemented Sequence Successfully");
544
+ },
545
+ handleInverse
546
+ })
547
+ );
548
+
549
+ const getEditorState = createSelector(
550
+ (state) => state.VectorEditor,
551
+ (state, editorName) => editorName,
552
+ (VectorEditor, editorName) => {
553
+ return VectorEditor[editorName];
554
+ }
555
+ );
556
+
557
+ function mapStateToProps(state, ownProps) {
558
+ const {
559
+ editorName,
560
+ sequenceData: sequenceDataFromProps,
561
+ allowSeqDataOverride,
562
+ allowMultipleFeatureDirections
563
+ } = ownProps;
564
+ const editorState = getEditorState(state, editorName);
565
+ const meta = { editorName };
566
+ const { VectorEditor } = state;
567
+ const { __allEditorsOptions } = VectorEditor;
568
+ const { uppercaseSequenceMapFont } = __allEditorsOptions;
569
+
570
+ if (!editorState) {
571
+ return editorReducer({}, {});
572
+ }
573
+
574
+ const { findTool, annotationsToSupport = {} } = editorState;
575
+ const visibilities = getVisibilities(editorState);
576
+ let annotationToAdd;
577
+ [
578
+ ["AddOrEditFeatureDialog", "filteredFeatures", "features"],
579
+ ["AddOrEditPrimerDialog", "filteredPrimers", "primers"],
580
+ ["AddOrEditPartDialog", "filteredParts", "parts"]
581
+ ].forEach(([n, type, annotationTypePlural]) => {
582
+ const vals = getFormValues(n)(state);
583
+ if (vals) {
584
+ annotationToAdd = getAnnToAdd(vals, n, type, annotationTypePlural);
585
+ }
586
+ });
587
+
588
+ const toReturn = {
589
+ ...editorState,
590
+ meta,
591
+ annotationToAdd
592
+ };
593
+
594
+ if (sequenceDataFromProps && allowSeqDataOverride) {
595
+ //return early here because we don't want to override the sequenceData being passed in
596
+ //this is a little hacky but allows us to track selectionLayer/caretIndex using redux but on a sequence that isn't being stored alongside that info
597
+ return toReturn;
598
+ }
599
+
600
+ const filteredCutsites = s.filteredCutsitesSelector(
601
+ editorState,
602
+ ownProps.additionalEnzymes,
603
+ ownProps.enzymeGroupsOverride
604
+ );
605
+ const cutsites = filteredCutsites.cutsitesArray;
606
+ const filteredRestrictionEnzymes =
607
+ s.filteredRestrictionEnzymesSelector(editorState);
608
+ const isEnzymeFilterAnd = s.isEnzymeFilterAndSelector(editorState);
609
+ // const orfs = s.orfsSelector(editorState);
610
+ const selectedCutsites = s.selectedCutsitesSelector(editorState);
611
+ const allCutsites = s.cutsitesSelector(
612
+ editorState,
613
+ ownProps.additionalEnzymes
614
+ );
615
+ const sequenceLength = s.sequenceLengthSelector(editorState);
616
+
617
+ const { matchedSearchLayer, searchLayers, matchesTotal } =
618
+ getSearchLayersAndMatch(editorState);
619
+ const annotationSearchMatches = s.annotationSearchSelector(editorState);
620
+
621
+ const _sequenceDataToUse = getSequenceDataToUse(
622
+ editorState,
623
+ cutsites,
624
+ __allEditorsOptions
625
+ );
626
+
627
+ const [sequenceDataToUse, newSelection] = getSeqDataWithAnnToAdd(
628
+ _sequenceDataToUse,
629
+ annotationToAdd,
630
+ allowMultipleFeatureDirections
631
+ );
632
+
633
+ const f = getFindTool(findTool, matchesTotal);
634
+ return {
635
+ ...editorState,
636
+ meta,
637
+ annotationToAdd,
638
+ ...(newSelection && { selectionLayer: newSelection }),
639
+ selectedCutsites,
640
+ sequenceLength,
641
+ allCutsites,
642
+ filteredCutsites,
643
+ filteredRestrictionEnzymes,
644
+ isEnzymeFilterAnd,
645
+ annotationSearchMatches,
646
+ searchLayers,
647
+ matchedSearchLayer,
648
+ findTool: f,
649
+ annotationsToSupport,
650
+ annotationVisibility: visibilities.annotationVisibilityToUse,
651
+ typesToOmit: visibilities.typesToOmit,
652
+ annotationLabelVisibility: visibilities.annotationLabelVisibilityToUse,
653
+ sequenceData: sequenceDataToUse,
654
+ uppercaseSequenceMapFont,
655
+ showGCContent: getShowGCContent(state, ownProps)
656
+ };
657
+ }
658
+
659
+ export function mapDispatchToActions(dispatch, ownProps) {
660
+ const { editorName } = ownProps;
661
+
662
+ const { actionOverrides = fakeActionOverrides } = ownProps;
663
+ const actionsToPass = getCombinedActions(
664
+ editorName,
665
+ actions,
666
+ actionOverrides,
667
+ dispatch
668
+ );
669
+ const updateSel =
670
+ ownProps.selectionLayerUpdate || actionsToPass.selectionLayerUpdate;
671
+ const updateCar =
672
+ ownProps.caretPositionUpdate || actionsToPass.caretPositionUpdate;
673
+ return {
674
+ ...actionsToPass,
675
+ selectionLayerUpdate: ownProps.onSelectionOrCaretChanged
676
+ ? (selectionLayer) => {
677
+ ownProps.onSelectionOrCaretChanged({
678
+ selectionLayer,
679
+ caretPosition: -1
680
+ });
681
+ updateSel(selectionLayer);
682
+ }
683
+ : updateSel,
684
+ caretPositionUpdate: ownProps.onSelectionOrCaretChanged
685
+ ? (caretPosition) => {
686
+ ownProps.onSelectionOrCaretChanged({
687
+ caretPosition,
688
+ selectionLayer: { start: -1, end: -1 }
689
+ });
690
+ updateCar(caretPosition);
691
+ }
692
+ : updateCar,
693
+
694
+ dispatch
695
+ };
696
+ }
697
+
698
+ const defaultOverrides = {};
699
+ export function fakeActionOverrides() {
700
+ return defaultOverrides;
701
+ }
702
+
703
+ export function getCombinedActions(
704
+ editorName,
705
+ actions,
706
+ actionOverrides,
707
+ dispatch
708
+ ) {
709
+ const meta = { editorName };
710
+
711
+ let metaActions = addMetaToActionCreators(actions, meta);
712
+ // let overrides = addMetaToActionCreators(actionOverrides(metaActions), meta);
713
+ const overrides = {};
714
+ metaActions = {
715
+ undo: () => {
716
+ window.toastr.success("Undo Successful");
717
+ return {
718
+ type: "VE_UNDO",
719
+ meta: {
720
+ editorName
721
+ }
722
+ };
723
+ },
724
+ redo: () => {
725
+ window.toastr.success("Redo Successful");
726
+ return {
727
+ type: "VE_REDO",
728
+ meta: {
729
+ editorName
730
+ }
731
+ };
732
+ },
733
+ ...metaActions,
734
+ ...overrides
735
+ };
736
+ //add meta to all action creators before passing them to the override function
737
+ // var metaActions = addMetaToActionCreators(actions, meta)
738
+ // let metaOverrides = addMetaToActionCreators(
739
+ // actionOverrides(metaActions),
740
+ // meta
741
+ // );
742
+
743
+ //rebind the actions with dispatch and meta
744
+ const actionsToPass = {
745
+ ...metaActions
746
+ // ...metaOverrides
747
+ };
748
+ return bindActionCreators(actionsToPass, dispatch);
749
+ }
750
+
751
+ function truncateOriginSpanningAnnotations(seqData) {
752
+ const {
753
+ features = [],
754
+ parts = [],
755
+ translations = [],
756
+ primers = [],
757
+ sequence
758
+ } = seqData;
759
+ return {
760
+ ...seqData,
761
+ features: truncateOriginSpanners(features, sequence.length),
762
+ parts: truncateOriginSpanners(parts, sequence.length),
763
+ translations: truncateOriginSpanners(translations, sequence.length),
764
+ primers: truncateOriginSpanners(primers, sequence.length)
765
+ };
766
+ }
767
+
768
+ function truncateOriginSpanners(annotations, sequenceLength) {
769
+ return map(annotations, (annotation) => {
770
+ const { start = 0, end = 0 } = annotation;
771
+ if (start > end) {
772
+ return {
773
+ ...annotation,
774
+ end: sequenceLength - 1
775
+ };
776
+ } else {
777
+ return annotation;
778
+ }
779
+ });
780
+ }
781
+
782
+ function hasAnnotationThatSpansOrigin({
783
+ features = [],
784
+ parts = [],
785
+ translations = [],
786
+ primers = []
787
+ }) {
788
+ return (
789
+ doAnySpanOrigin(features) ||
790
+ doAnySpanOrigin(parts) ||
791
+ doAnySpanOrigin(translations) ||
792
+ doAnySpanOrigin(primers)
793
+ );
794
+ }
795
+ function doAnySpanOrigin(annotations) {
796
+ return some(annotations, ({ start = 0, end = 0 }) => {
797
+ if (start > end) return true;
798
+ });
799
+ }
800
+
801
+ export const connectToEditor = (fn) => {
802
+ return connect(
803
+ (state, ownProps, ...rest) => {
804
+ const editor = state.VectorEditor[ownProps.editorName] || {};
805
+ editor.sequenceData = editor.sequenceData || {};
806
+ editor.sequenceData.sequence = getUpperOrLowerSeq(
807
+ state.VectorEditor.__allEditorsOptions.uppercaseSequenceMapFont,
808
+ editor.sequenceData.sequence
809
+ );
810
+
811
+ return fn ? fn(editor, ownProps, ...rest, state) : {};
812
+ },
813
+ mapDispatchToActions
814
+ // function mergeProps(propsFromState, propsFromDispatch) {
815
+ // return {
816
+ // ...propsFromState,
817
+ // ...propsFromDispatch
818
+ // };
819
+ // }
820
+ );
821
+ };
822
+
823
+ //this is to enhance non-redux connected views like LinearView, or CircularView or RowView
824
+ //so they can still render things like translations, ..etc
825
+
826
+ //Currently only supporting translations
827
+ export const withEditorPropsNoRedux = withProps((props) => {
828
+ const {
829
+ sequenceData,
830
+ sequenceDataWithRefSeqCdsFeatures,
831
+ annotationVisibility,
832
+ annotationVisibilityOverrides
833
+ } = props;
834
+ const translations = s.translationsSelector({
835
+ sequenceData: sequenceDataWithRefSeqCdsFeatures || sequenceData,
836
+ annotationVisibility: {
837
+ ...annotationVisibility,
838
+ ...annotationVisibilityOverrides
839
+ }
840
+ });
841
+ const toReturn = {
842
+ sequenceData: {
843
+ ...sequenceData,
844
+ translations
845
+ }
846
+ };
847
+ return toReturn;
848
+ });
849
+
850
+ export function getShowGCContent(state, ownProps) {
851
+ const showGCContent = state.VectorEditor.__allEditorsOptions.showGCContent;
852
+
853
+ const toRet =
854
+ showGCContent === null
855
+ ? ownProps.showGCContentByDefault //user hasn't yet set this option
856
+ : showGCContent;
857
+ return toRet;
858
+ }
859
+
860
+ function jsonToJson(incomingJson) {
861
+ return JSON.stringify(
862
+ omit(
863
+ cleanUpTeselagenJsonForExport(
864
+ tidyUpSequenceData(incomingJson, { annotationsAsObjects: false })
865
+ ),
866
+ [
867
+ "sequenceFragments",
868
+ "sequenceFeatures",
869
+ "cutsites",
870
+ "orfs",
871
+ "filteredParts",
872
+ "filteredFeatures",
873
+ "filteredPrimers"
874
+ ]
875
+ )
876
+ );
877
+ }
878
+
879
+ const getSearchLayersAndMatch = createSelector(
880
+ (ed) => ed.findTool,
881
+ s.searchLayersSelector,
882
+ (findTool, _searchLayers) => {
883
+ let searchLayers;
884
+ let matchedSearchLayer = { start: -1, end: -1 };
885
+ searchLayers = _searchLayers.map((item, index) => {
886
+ let itemToReturn = item;
887
+ if (index === findTool.matchNumber) {
888
+ itemToReturn = {
889
+ ...item,
890
+ className: item.className + " veSearchLayerActive"
891
+ };
892
+ matchedSearchLayer = itemToReturn;
893
+ }
894
+ return itemToReturn;
895
+ });
896
+ const matchesTotal = searchLayers.length;
897
+ if (
898
+ (!findTool.highlightAll && searchLayers[findTool.matchNumber]) ||
899
+ searchLayers.length > MAX_MATCHES_DISPLAYED
900
+ ) {
901
+ searchLayers = [searchLayers[findTool.matchNumber]];
902
+ }
903
+ return {
904
+ matchesTotal,
905
+ searchLayers,
906
+ matchedSearchLayer
907
+ };
908
+ }
909
+ );
910
+ const getSequenceDataToUse = createSelector(
911
+ (a, b, __allEditorsOptions) => __allEditorsOptions.uppercaseSequenceMapFont,
912
+ (ed) => ed.sequenceData,
913
+ (ed, cutsites) => cutsites,
914
+ s.translationsSelector,
915
+ s.filteredFeaturesSelector,
916
+ s.filteredPrimersSelector,
917
+ s.filteredPartsSelector,
918
+ s.orfsSelector,
919
+ (
920
+ uppercaseSequenceMapFont,
921
+ sequenceData,
922
+ cutsites,
923
+ translations,
924
+ filteredFeatures,
925
+ filteredPrimers,
926
+ filteredParts,
927
+ orfs
928
+ ) => {
929
+ return {
930
+ ...sequenceData,
931
+ sequence: getUpperOrLowerSeq(
932
+ uppercaseSequenceMapFont,
933
+ sequenceData.sequence
934
+ ),
935
+ filteredParts,
936
+ filteredFeatures,
937
+ filteredPrimers,
938
+ cutsites,
939
+ orfs,
940
+ translations
941
+ };
942
+ }
943
+ );
944
+
945
+ const getFindTool = createSelector(
946
+ (f) => f,
947
+ (f, m) => m,
948
+ (findTool, matchesTotal) => {
949
+ return {
950
+ ...findTool,
951
+ matchesTotal
952
+ };
953
+ }
954
+ );
955
+
956
+ const getAnnToAdd = defaultMemoize((vals, n, type, annotationTypePlural) => {
957
+ const annToAdd = {
958
+ color: getFeatureToColorMap({ includeHidden: true })[
959
+ vals.type || "primer_bind"
960
+ ], //we won't have the correct color yet so we set it here
961
+ ...vals,
962
+ formName: n,
963
+ type,
964
+ annotationTypePlural,
965
+ name: vals.name || "Untitled"
966
+ };
967
+ if (!vals.useLinkedOligo) {
968
+ delete annToAdd.bases;
969
+ }
970
+ return annToAdd;
971
+ });
972
+ const getSeqDataWithAnnToAdd = defaultMemoize(
973
+ (seqData, ann, allowMultipleFeatureDirections) => {
974
+ if (ann) {
975
+ const selectionLayer = convertRangeTo0Based(ann);
976
+ delete selectionLayer.color;
977
+ const id = ann.id || "tempId123";
978
+ const name = ann.name || "";
979
+ const anns = keyBy(seqData[ann.type], "id");
980
+ let toSpread = {};
981
+ if (
982
+ ann.annotationTypePlural === "features" &&
983
+ allowMultipleFeatureDirections &&
984
+ ann.arrowheadType !== undefined
985
+ ) {
986
+ toSpread = {
987
+ forward: ann.arrowheadType !== "BOTTOM",
988
+ arrowheadType: ann.arrowheadType
989
+ };
990
+ }
991
+ anns[id] = {
992
+ ...ann,
993
+ id,
994
+ name,
995
+ ...selectionLayer,
996
+ ...(ann.bases && {
997
+ // ...getStartEndFromBases({ ...ann, sequenceLength }),
998
+ fullSeq: seqData.sequence
999
+ }),
1000
+ ...toSpread,
1001
+ locations: ann.locations
1002
+ ? ann.locations.map(convertRangeTo0Based)
1003
+ : undefined
1004
+ };
1005
+
1006
+ return [{ ...seqData, [ann.type]: anns }, selectionLayer];
1007
+ }
1008
+ return [seqData];
1009
+ }
1010
+ );