├── .github └── workflows │ └── build.yml ├── .gitignore ├── .husky └── pre-commit ├── .prettierignore ├── .prettierrc ├── .versionrc ├── .vscode └── settings.json ├── CHANGELOG.md ├── README.md ├── dev ├── 1_annotations.json ├── 1_config.json ├── 2_annotations.json ├── 2_config.json ├── 3_annotations.json ├── 4_annotations.json ├── attributes_with_no_required_properties_config.json ├── development-sever.js ├── development.html ├── dummy_auth_page.html ├── elon.md ├── favicon.ico ├── for_import.txt ├── invalid.json ├── invalid_attributes_annotation.json ├── invalid_blocks_only.json ├── invalid_color_annotation.json ├── invalid_color_config.json ├── invalid_multi.json ├── multi_tracks.json ├── outer.css ├── prefix.json ├── private.json ├── target.txt ├── warning_not_integer_span.json └── ゆりかごのうた.json ├── dist ├── demo │ ├── bionlp-st-ge │ │ ├── demo-annotations.json │ │ ├── demo-cdn.html │ │ ├── demo-config.json │ │ ├── demo-empty.html │ │ ├── demo-local.html │ │ └── demo-multi.html │ ├── development.html │ └── initial_load_error.html ├── editor.html └── lib │ ├── css │ ├── images │ │ ├── btn_adjust_lineheight_16.png │ │ ├── btn_auto_adjust_lineheight_16.png │ │ ├── btn_auto_replicate_16.png │ │ ├── btn_block_edit_mode_16.png │ │ ├── btn_boundary_detection_16.png │ │ ├── btn_copy_16.png │ │ ├── btn_create_span_by_touch_16.png │ │ ├── btn_cut_16.png │ │ ├── btn_delete_16.png │ │ ├── btn_edit_properties_16.png │ │ ├── btn_edit_text_by_touch_16.png │ │ ├── btn_expand_span_by_touch_16.png │ │ ├── btn_help_16.png │ │ ├── btn_import_16.png │ │ ├── btn_new_entity_16.png │ │ ├── btn_pallet_16.png │ │ ├── btn_pallet_modified_16.png │ │ ├── btn_paste_16.png │ │ ├── btn_redo_16.png │ │ ├── btn_relation_edit_mode_16.png │ │ ├── btn_replicate_span_annotation_16.png │ │ ├── btn_setting_16.png │ │ ├── btn_shrink_span_by_touch_16.png │ │ ├── btn_simple_view_16.png │ │ ├── btn_term_edit_mode_16.png │ │ ├── btn_text_edit_mode_16.png │ │ ├── btn_undo_16.png │ │ ├── btn_upload_16.png │ │ ├── btn_upload_automatically_16.png │ │ ├── btn_upload_modified_16.png │ │ ├── btn_view_mode_16.png │ │ ├── keyhelp.png │ │ ├── link.png │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_228ef1_256x240.png │ │ ├── ui-icons_ef8c08_256x240.png │ │ ├── ui-icons_ffd27a_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── textae-14.0.1.css │ └── textae-14.0.1.min.css │ ├── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.ttf │ ├── fontawesome-webfont.woff │ └── fontawesome-webfont.woff2 │ ├── textae-14.0.1.js │ └── textae-14.0.1.min.js ├── eslint.config.mjs ├── package-lock.json ├── package.json ├── scripts └── postinstall.js ├── src ├── app │ └── editor.html ├── demo │ ├── bionlp-st-ge │ │ ├── demo-annotations.json │ │ ├── demo-cdn.html │ │ ├── demo-config.json │ │ ├── demo-empty.html │ │ ├── demo-local.html │ │ └── demo-multi.html │ ├── development.html │ └── initial_load_error.html ├── index.js └── lib │ ├── AttributeDefinition.js │ ├── Editor │ ├── AnnotationModel │ │ ├── AnnotationEvaluator │ │ │ ├── getAllSpansIn.js │ │ │ ├── getAllSpansOf.js │ │ │ ├── index.js │ │ │ ├── parseTracks.js │ │ │ ├── readAcceptedAnnotationTo │ │ │ │ ├── IDConflictResolver.js │ │ │ │ ├── convertBeginAndEndOfSpanToInteger.js │ │ │ │ └── index.js │ │ │ └── validateAnnotation │ │ │ │ ├── ChainValidation │ │ │ │ ├── index.js │ │ │ │ └── setSourceProperty.js │ │ │ │ ├── ErrorMap.js │ │ │ │ ├── debugLogCrossing.js │ │ │ │ ├── getSpanValidation │ │ │ │ ├── index.js │ │ │ │ └── isBeginAndEndIn │ │ │ │ │ ├── index.js │ │ │ │ │ └── isInText.js │ │ │ │ ├── index.js │ │ │ │ ├── isContains.js │ │ │ │ ├── isIDUnique.js │ │ │ │ ├── transformToReferencedEntitiesError.js │ │ │ │ ├── validateAttribute │ │ │ │ ├── index.js │ │ │ │ └── isUniqueIn.js │ │ │ │ ├── validateBlock.js │ │ │ │ ├── validateDenotation.js │ │ │ │ ├── validateRelation.js │ │ │ │ └── validateTypeSettings.js │ │ ├── AttributeInstanceContainer │ │ │ ├── AttributeInstance.js │ │ │ ├── MediaDictionary.js │ │ │ └── index.js │ │ ├── DefinedType.js │ │ ├── DefinitionContainer │ │ │ ├── DefinedTypeContainer │ │ │ │ ├── getForwardMatchID │ │ │ │ │ ├── getForwardMatchTypes.js │ │ │ │ │ ├── getLongestIdMatchType.js │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ ├── countUsage.js │ │ │ ├── formatForPallet │ │ │ │ ├── createTypesWithoutInstance.js │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ └── sortByCountAndName.js │ │ ├── EntityInstanceContainer.js │ │ ├── IdIssueContainer │ │ │ └── index.js │ │ ├── InstanceContainer │ │ │ ├── index.js │ │ │ └── isFunction.js │ │ ├── LineHeightAuto.js │ │ ├── RelationInstanceContainer │ │ │ ├── RelationInstance │ │ │ │ ├── Arrow │ │ │ │ │ ├── CurveAlgorithmFactory │ │ │ │ │ │ ├── ArchedCurveAlgorithm.js │ │ │ │ │ │ ├── BentOnSourceCurveAlgorithm.js │ │ │ │ │ │ ├── BentOnTargetCurveAlgorithm.js │ │ │ │ │ │ ├── CurveAlgorithm.js │ │ │ │ │ │ ├── CutOffOnSourceArchedCurveAlgorithm.js │ │ │ │ │ │ ├── CutOffOnSourceBentOnSourceCurveAlgorithm.js │ │ │ │ │ │ ├── CutOffOnSourceBentOnTargetCurveAlgorithm.js │ │ │ │ │ │ ├── CutOffOnTargetArchedCurveAlgorithm.js │ │ │ │ │ │ ├── CutOffOnTargetBentOnSourceCurveAlgorithm.js │ │ │ │ │ │ ├── CutOffOnTargetBentOnTargetCurveAlgorithm.js │ │ │ │ │ │ ├── PointingDownCurveAlgorithm.js │ │ │ │ │ │ ├── PointingUpCurveAlgorithm.js │ │ │ │ │ │ ├── StartAndEnd.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── MarkerHeight.js │ │ │ │ │ ├── createJetty.js │ │ │ │ │ ├── createPath.js │ │ │ │ │ ├── createSourceBollard.js │ │ │ │ │ ├── createTargetBollard.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── moveJetty.js │ │ │ │ │ └── updatePath.js │ │ │ │ ├── Label.js │ │ │ │ ├── NS.js │ │ │ │ ├── index.js │ │ │ │ └── toDisplayName │ │ │ │ │ ├── getDisplayNameTag.js │ │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── SpanInstanceContainer │ │ │ ├── BlockSpanInstance │ │ │ │ ├── index.js │ │ │ │ ├── renderBackground.js │ │ │ │ └── setPosition.js │ │ │ ├── DenotationSpanInstance │ │ │ │ ├── getGridHeightIncludeDescendantGrids.js │ │ │ │ └── index.js │ │ │ ├── SELECTED.js │ │ │ ├── SpanInstance │ │ │ │ ├── createGridHtml.js │ │ │ │ ├── getRightGrid.js │ │ │ │ ├── index.js │ │ │ │ └── updateGridPosition │ │ │ │ │ ├── index.js │ │ │ │ │ └── isStaying.js │ │ │ ├── SpanMap.js │ │ │ ├── StyleSpanInstance.js │ │ │ ├── TextSelection │ │ │ │ ├── getOffsetFromParent.js │ │ │ │ ├── getParentOffset.js │ │ │ │ └── index.js │ │ │ ├── createRangeToSpan │ │ │ │ ├── createRange.js │ │ │ │ ├── getRenderingPosition │ │ │ │ │ ├── getOffset.js │ │ │ │ │ ├── getRenderingPositionFromBigBrother.js │ │ │ │ │ ├── getRenderingPositionFromParent.js │ │ │ │ │ └── index.js │ │ │ │ └── index.js │ │ │ ├── getCurrentMaxHeight.js │ │ │ ├── index.js │ │ │ ├── rangeFrom.js │ │ │ ├── spanComparator.js │ │ │ └── updateSpanTree │ │ │ │ ├── getParent │ │ │ │ ├── index.js │ │ │ │ └── isChildOf.js │ │ │ │ └── index.js │ │ ├── TypeDictionary.js │ │ ├── TypeGap.js │ │ ├── createTextBox │ │ │ ├── TextBox │ │ │ │ ├── getLineHeight.js │ │ │ │ ├── index.js │ │ │ │ ├── pixelToInt.js │ │ │ │ ├── setLineHeight.js │ │ │ │ └── updateTextBoxHeight.js │ │ │ ├── focusEditorWhenFocusedChildRemoved.js │ │ │ └── index.js │ │ ├── getAnnotationBox.js │ │ ├── getBoundaryCrossingSpans.js │ │ ├── getReplicationRanges │ │ │ ├── getDuplicateSentenceFromText.js │ │ │ ├── index.js │ │ │ └── isWord.js │ │ ├── index.js │ │ ├── isBoundaryCrossingWithOtherSpans.js │ │ ├── toBlocks.js │ │ ├── toDenotations.js │ │ └── toRelations.js │ ├── AnnotationModelEventsObserver.js │ ├── AttributeDefinitionContainer │ │ ├── createAttributeDefinition │ │ │ ├── FlagAttributeDefinition.js │ │ │ ├── SelectionAttributeDefinition.js │ │ │ ├── StringAttributeDefinition.js │ │ │ └── index.js │ │ └── index.js │ ├── BrowserEventListener.js │ ├── DataSource.js │ ├── EditorCSSClass.js │ ├── EditorEventListener.js │ ├── EntityInstance.js │ ├── RESOURCE_TYPE.js │ ├── RemoteResource │ │ ├── AnnotationLoader │ │ │ ├── index.js │ │ │ └── parseResponse │ │ │ │ ├── index.js │ │ │ │ └── responseTypes.js │ │ ├── AnnotationSaver │ │ │ ├── index.js │ │ │ ├── prepareRequestBody.js │ │ │ └── waitForPopUpClose.js │ │ ├── ConfigurationLoader.js │ │ ├── ConfigurationSaver.js │ │ ├── index.js │ │ ├── isServerPageAuthRequired.js │ │ └── openPopUp.js │ ├── SelectionModel │ │ ├── SelectedItems.js │ │ ├── SelectedItemsWithAttributes.js │ │ └── index.js │ ├── SignboardHTMLElement.js │ ├── StartUpOptions │ │ ├── AnnotationResource.js │ │ └── index.js │ ├── UseCase │ │ ├── AnnotationAutoSaver.js │ │ ├── Clipboard │ │ │ └── index.js │ │ ├── Commander │ │ │ ├── Factory │ │ │ │ ├── AddValueToAttributeDefinitionCommand.js │ │ │ │ ├── AnnotationCommand.js │ │ │ │ ├── BaseCommand.js │ │ │ │ ├── ChangeAnnotationCommand.js │ │ │ │ ├── ChangeAttributeCommand.js │ │ │ │ ├── ChangeAttributeDefinitionAndReflectInstancesCommand │ │ │ │ │ ├── ChangeAttributeDefinitionCommand │ │ │ │ │ │ ├── applyChangedProperties.js │ │ │ │ │ │ └── index.js │ │ │ │ │ └── index.js │ │ │ │ ├── ChangeAttributeObjOfItemsCommand.js │ │ │ │ ├── ChangeStringAttributeObjOfItemsCommand.js │ │ │ │ ├── ChangeTextAndMoveSpanCommand.js │ │ │ │ ├── ChangeTextCommand.js │ │ │ │ ├── ChangeTypeDefinitionAndReflectInstancesCommand │ │ │ │ │ ├── createChangeAnnotationCommands.js │ │ │ │ │ └── index.js │ │ │ │ ├── ChangeTypeDefinitionCommand │ │ │ │ │ ├── applyChangedProperties.js │ │ │ │ │ └── index.js │ │ │ │ ├── ChangeTypeNameAndAttributeOfSelectedItemsCommand │ │ │ │ │ ├── getChangeAttributeCommands.js │ │ │ │ │ └── index.js │ │ │ │ ├── ChangeTypeOfSelectedItemsCommand.js │ │ │ │ ├── ChangeTypeValuesCommand.js │ │ │ │ ├── ChangeValueOfAttributeDefinitionAndObjectOfAttributeCommand │ │ │ │ │ ├── ChangeValueOfAttributeDefinitionCommand.js │ │ │ │ │ └── index.js │ │ │ │ ├── CompositeCommand.js │ │ │ │ ├── ConfigurationCommand.js │ │ │ │ ├── CreateAttributeDefinitionCommand.js │ │ │ │ ├── CreateAttributeToItemsCommand.js │ │ │ │ ├── CreateBlockSpanCommand.js │ │ │ │ ├── CreateDefaultTypeEntityToSelectedSpansCommand.js │ │ │ │ ├── CreateDenotationSpanAndTypesCommand.js │ │ │ │ ├── CreateEntityAndAttributesCommand │ │ │ │ │ ├── CreateAttributeToTheLatestEntityCommand.js │ │ │ │ │ └── index.js │ │ │ │ ├── CreateSpanAndAutoReplicateCommand.js │ │ │ │ ├── CreateTypeDefinitionCommand.js │ │ │ │ ├── DeleteAttributeDefinitionCommand.js │ │ │ │ ├── MoveAttributeDefinitionCommand.js │ │ │ │ ├── MoveBlockSpanCommand.js │ │ │ │ ├── MoveDenotationSpanCommand.js │ │ │ │ ├── MoveEntitiesToSelectedDenotationSpanCommand │ │ │ │ │ ├── MoveEntitiesToSpanCommand │ │ │ │ │ │ ├── RevertMoveEntitiesCommand.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── areAllEntitiesOfSpan.js │ │ │ │ │ └── index.js │ │ │ │ ├── PasteTypesToSelectedDenotationSpansCommand.js │ │ │ │ ├── RemoveAttributesFromItemsByPredCommand.js │ │ │ │ ├── RemoveEntityAndAssociatesCommand.js │ │ │ │ ├── RemoveRelationAndAssociatesCommand.js │ │ │ │ ├── RemoveSelectedCommand.js │ │ │ │ ├── RemoveSpanCommand.js │ │ │ │ ├── RemoveTypeDefinitionCommand.js │ │ │ │ ├── RemoveValueFromAttributeDefinitionCommand.js │ │ │ │ ├── ReplicateSpanCommand.js │ │ │ │ ├── ToggleFlagAttributeToItemsCommand.js │ │ │ │ ├── aggregateTargetEntities.js │ │ │ │ ├── aggregateTargetRelations.js │ │ │ │ ├── commandLog.js │ │ │ │ ├── commandTemplate.js │ │ │ │ ├── createChangeConfigCommand.js │ │ │ │ ├── getAddPatternToStringAttributeDefinitionCommand.js │ │ │ │ ├── getCreateAttributeToItemsCommands.js │ │ │ │ ├── getRemoveAttributesByPredCommands.js │ │ │ │ └── index.js │ │ │ ├── History.js │ │ │ └── index.js │ │ ├── EditModeState.js │ │ ├── FunctionAvailability │ │ │ ├── Translator.js │ │ │ └── index.js │ │ ├── IconEventMap.js │ │ ├── KeyEventMap.js │ │ ├── MenuState │ │ │ ├── BlankSkipAdjuster.js │ │ │ ├── Buttons │ │ │ │ ├── Button.js │ │ │ │ ├── Section.js │ │ │ │ ├── definition.js │ │ │ │ └── index.js │ │ │ ├── DelimiterDetectAdjuster │ │ │ │ ├── backToDelimiter.js │ │ │ │ ├── backToWord.js │ │ │ │ ├── getNext.js │ │ │ │ ├── getPrev.js │ │ │ │ ├── index.js │ │ │ │ ├── isNotWord.js │ │ │ │ ├── skipToDelimiter.js │ │ │ │ └── skipToWord.js │ │ │ ├── EnableState.js │ │ │ ├── PushButtons │ │ │ │ ├── PushButton.js │ │ │ │ └── index.js │ │ │ ├── TextSelectionAdjuster.js │ │ │ ├── index.js │ │ │ ├── reduce2hash.js │ │ │ ├── skipBlank.js │ │ │ └── skipCharacters.js │ │ ├── OriginalData │ │ │ ├── StatusBar │ │ │ │ ├── getAreaIn.js │ │ │ │ ├── html.js │ │ │ │ └── index.js │ │ │ └── index.js │ │ ├── PersistenceInterface │ │ │ ├── LastLoadedFilename.js │ │ │ ├── LastLoadedURL.js │ │ │ ├── index.js │ │ │ ├── isTxtFile.js │ │ │ ├── readAnnotationFile │ │ │ │ ├── index.js │ │ │ │ └── parseFileContent.js │ │ │ ├── readAnnotationText.js │ │ │ ├── readConfigurationFile.js │ │ │ └── readFile.js │ │ ├── Presenter │ │ │ ├── EditModeSwitch │ │ │ │ ├── AttributeEditor │ │ │ │ │ ├── createNumericAttributeOrShowEditNumericAttributeDialog.js │ │ │ │ │ ├── createStringAttributeOrShowEditStringAttributeDialog.js │ │ │ │ │ └── index.js │ │ │ │ ├── BlockEditMode │ │ │ │ │ ├── MouseEventHandler.js │ │ │ │ │ ├── SpanEditor.js │ │ │ │ │ ├── create.js │ │ │ │ │ └── index.js │ │ │ │ ├── EditMode │ │ │ │ │ ├── PropertyEditor.js │ │ │ │ │ └── index.js │ │ │ │ ├── ModeTransitionReactor │ │ │ │ │ ├── EditorCSS.js │ │ │ │ │ └── index.js │ │ │ │ ├── PalletFactory │ │ │ │ │ ├── bindPalletEvents │ │ │ │ │ │ ├── checkButtonEnable.js │ │ │ │ │ │ └── index.js │ │ │ │ │ └── index.js │ │ │ │ ├── RelationEditMode │ │ │ │ │ ├── MouseEventHandler │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ └── typeValuesClicked │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ └── updateSelectionOfEntity.js │ │ │ │ │ └── index.js │ │ │ │ ├── SelectionWrapper │ │ │ │ │ ├── index.js │ │ │ │ │ ├── isNodeBlockSpan.js │ │ │ │ │ ├── isNodeDenotationSpan.js │ │ │ │ │ ├── isNodeStyleSpan.js │ │ │ │ │ └── isNodeTextBox.js │ │ │ │ ├── TermEditMode │ │ │ │ │ ├── MouseEventHandler.js │ │ │ │ │ ├── SpanEditor │ │ │ │ │ │ ├── create.js │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ ├── isInSelected.js │ │ │ │ │ │ └── isPositionBetweenSpan.js │ │ │ │ │ └── index.js │ │ │ │ ├── TextEditMode │ │ │ │ │ ├── TextEditDialog.js │ │ │ │ │ └── index.js │ │ │ │ ├── clearTextSelection.js │ │ │ │ ├── index.js │ │ │ │ ├── isTextSelectionInTextBox.js │ │ │ │ ├── selectSpan.js │ │ │ │ └── shrinkSpan │ │ │ │ │ ├── index.js │ │ │ │ │ └── shrinkSpanToSelection.js │ │ │ ├── Horizontal.js │ │ │ ├── Vertical.js │ │ │ ├── getIsDelimiterFunc.js │ │ │ └── index.js │ │ ├── SpanConfig.js │ │ ├── getEntityHTMLelementFromChild.js │ │ ├── index.js │ │ ├── initAnnotation │ │ │ ├── index.js │ │ │ └── setLoadedAnnotation.js │ │ ├── patchConfiguration │ │ │ ├── AttributeConfigurationGenerator │ │ │ │ ├── AnnotationsForPred │ │ │ │ │ ├── getMostFrequentObject.js │ │ │ │ │ ├── getStep.js │ │ │ │ │ ├── getValueType.js │ │ │ │ │ └── index.js │ │ │ │ ├── fillDefaultValueOfSelectionAttributes │ │ │ │ │ ├── getSelectionAttributes.js │ │ │ │ │ └── index.js │ │ │ │ ├── fillInferDefinitionFromAnnotation │ │ │ │ │ ├── fill.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── inferDefinitionFromAnnotation │ │ │ │ │ │ └── index.js │ │ │ │ ├── fillMandatoryValueOfNumericAttributes.js │ │ │ │ ├── getAnnotationMap.js │ │ │ │ └── index.js │ │ │ ├── clone.js │ │ │ └── index.js │ │ ├── setAnnotationAndConfiguration.js │ │ ├── validateAttributeDefinitionAndAlert │ │ │ ├── hasAllValueDefinitionOfSelectionAttributes.js │ │ │ └── index.js │ │ ├── validateConfigurationAndAlert │ │ │ ├── index.js │ │ │ └── validateConfiguration │ │ │ │ ├── index.js │ │ │ │ └── toErrorMessage.js │ │ └── warningIfBeginEndOfSpanAreNotInteger │ │ │ ├── areNotBeginAndEndInteger.js │ │ │ └── index.js │ ├── control │ │ ├── ContextMenu │ │ │ ├── index.js │ │ │ └── toContextMenuItem.js │ │ ├── Menu │ │ │ ├── bindEventHandler.js │ │ │ └── index.js │ │ ├── ToolBar │ │ │ ├── index.js │ │ │ └── toButtonGroup │ │ │ │ ├── index.js │ │ │ │ └── toButtonIcon.js │ │ └── classify.js │ ├── diffOfAnnotation │ │ ├── byID.js │ │ ├── index.js │ │ └── sortByID.js │ ├── editorCSSClassObserve.js │ ├── filterIfModelModified.js │ ├── forwardMethods.js │ ├── getDisplayName │ │ ├── getDisplayNameFromUri.js │ │ └── index.js │ ├── getLabelBackgroundColor.js │ ├── getMatchPrefix.js │ ├── getPalletButtonTitleFor.js │ ├── getRightElement.js │ ├── getRightSpanElement.js │ ├── getURI.js │ ├── getUrlMatches.js │ ├── hexToRGBA.js │ ├── index.js │ ├── isAndroid.js │ ├── isBoundaryCrossing.js │ ├── isTouchable.js │ ├── loadAnnotation.js │ ├── observeElement.js │ ├── observeEventEmitter.js │ ├── round.js │ └── toAnchorElement.js │ ├── IntervalNotation │ ├── getLowwerCond.js │ ├── getUpperCond.js │ ├── gt.js │ ├── gte.js │ └── index.js │ ├── MODE.js │ ├── NumericAttributeDefinition.js │ ├── TypeValues.js │ ├── component │ ├── CreateAttributeDefinitionDialog │ │ ├── index.js │ │ └── template.js │ ├── CreateOrEditValueOfAttributeDefinitionDialog │ │ ├── index.js │ │ ├── inputDefault.js │ │ └── template.js │ ├── CreateTypeDefinitionDialog.js │ ├── Dialog.js │ ├── EditAttributeDefinitionDialog │ │ ├── index.js │ │ ├── isChanged.js │ │ └── template.js │ ├── EditNumericAttributeDialog.js │ ├── EditPropertiesDialog │ │ ├── EditAttributeButtonHandler.js │ │ ├── createContentHTML │ │ │ ├── index.js │ │ │ ├── toAddAttributeButton.js │ │ │ ├── toAttributeHTML │ │ │ │ ├── getLabelOf.js │ │ │ │ └── index.js │ │ │ └── toEntityHTML.js │ │ ├── getValues.js │ │ ├── index.js │ │ └── mergedTypeValuesOf.js │ ├── EditStringAttributeDialog.js │ ├── EditTypeDefinitionDialog │ │ ├── getDifference.js │ │ └── index.js │ ├── HelpDialog.js │ ├── LoadAnnotationDialog │ │ ├── index.js │ │ └── initInlineEditor.js │ ├── LoadConfigurationDialog.js │ ├── LoadDialogLocalComponent.js │ ├── LoadDialogURLComponent.js │ ├── Pallet │ │ ├── enableJqueryDraggable.js │ │ ├── index.js │ │ ├── setHeightWithin.js │ │ └── setWidthWithin.js │ ├── PromiseDialog.js │ ├── SaveAnnotationDialog │ │ ├── bind │ │ │ ├── createDownloadPathForFormat.js │ │ │ ├── downloadAnnotationFile │ │ │ │ ├── downloadAnnotation.js │ │ │ │ └── index.js │ │ │ ├── index.js │ │ │ └── viewSource.js │ │ └── index.js │ ├── SaveConfigurationDialog │ │ ├── bind.js │ │ ├── index.js │ │ └── jsonDiff.js │ ├── SelectionAttributePallet │ │ ├── index.js │ │ ├── template.js │ │ └── toBodyRow.js │ ├── SettingDialog │ │ ├── EscapeSequence.js │ │ ├── bindAddCharacter │ │ │ ├── addCharacterRow │ │ │ │ ├── index.js │ │ │ │ └── validateCharacter.js │ │ │ └── index.js │ │ ├── bindDeleteCharacter.js │ │ ├── index.js │ │ ├── reflectImmediately │ │ │ ├── bindChangeFunctionAvailability.js │ │ │ ├── bindChangeLineHeight.js │ │ │ ├── bindChangeLockConfig.js │ │ │ ├── bindChangeTypeGap.js │ │ │ ├── debounce300.js │ │ │ ├── index.js │ │ │ └── redrawAllEditor.js │ │ ├── saveAutocompletionWs.js │ │ ├── saveSpanConfig.js │ │ ├── template │ │ │ ├── escapeForDisplay.js │ │ │ ├── index.js │ │ │ ├── toBlankCharacterRowElement.js │ │ │ ├── toDelimiterCharacterRowElement.js │ │ │ └── toFunctionAvailabilityLabelElement.js │ │ └── validateConfiguration.js │ ├── TipsDialog.js │ ├── TypeDefinitionDialog │ │ ├── index.js │ │ └── template.js │ ├── TypeValuesPallet │ │ ├── bindAttributeEvent │ │ │ ├── enableAttributeTabDrag │ │ │ │ ├── hideDropTargets.js │ │ │ │ ├── index.js │ │ │ │ └── showDropTargets.js │ │ │ ├── enableAttributeTabDrop.js │ │ │ └── index.js │ │ ├── createContentHtml │ │ │ ├── flagAttributeTemplate.js │ │ │ ├── headerTemplate │ │ │ │ ├── addAttributeButtonTemplate.js │ │ │ │ ├── addNewAttributeTabTemplate.js │ │ │ │ ├── attributeTabTemplate.js │ │ │ │ ├── editAttributeButtonTemplate.js │ │ │ │ ├── getSelectedEntityLabel.js │ │ │ │ ├── index.js │ │ │ │ └── removeAttributeButtonTemplate.js │ │ │ ├── index.js │ │ │ ├── numericAttributeTemplate │ │ │ │ ├── index.js │ │ │ │ └── toBodyRow.js │ │ │ ├── predicateControllerTemplate │ │ │ │ ├── editAttributeDefinitionBlockTemplate.js │ │ │ │ ├── index.js │ │ │ │ └── toDeleteButton.js │ │ │ ├── selectionAttributeTemplate │ │ │ │ ├── index.js │ │ │ │ └── toBodyRow.js │ │ │ ├── showAddAttributeValueButton.js │ │ │ ├── stringAttributeTemplate │ │ │ │ ├── index.js │ │ │ │ └── toBodyRow.js │ │ │ ├── typeTemplate │ │ │ │ ├── editButtonsTemplate.js │ │ │ │ ├── index.js │ │ │ │ └── toTypeRow.js │ │ │ └── valueButtonsTemplate.js │ │ ├── enableDrag.js │ │ └── index.js │ ├── ValidationDialog │ │ ├── boundaryCrossingSpansTemplate.js │ │ ├── duplicateRangeBlocksTemplate.js │ │ ├── duplicatedAttributesTemplate.js │ │ ├── duplicatedIDsTemplate.js │ │ ├── index.js │ │ ├── outOfTextBlocksTemplate.js │ │ ├── outOfTextDenotationsTemplate.js │ │ ├── outOfTextTypesettingsTemplate.js │ │ ├── referencedEntitiesDoNotExistTemplate.js │ │ ├── wrongRangeBlocksTemplate.js │ │ ├── wrongRangeDenotationsTemplate.js │ │ └── wrongRangeTypesettingsTemplate.js │ ├── anemone.js │ ├── createDownloadPath.js │ ├── enableHTMLElement.js │ ├── fetchAutocompleteCandidates.js │ ├── getInputElementValue.js │ ├── getRandomColorString.js │ ├── initJSONEditor.js │ ├── inputAttributeDefinition │ │ ├── index.js │ │ ├── inputAutocompletionWs.js │ │ ├── inputDefault.js │ │ ├── inputLabelAndColor.js │ │ ├── inputMediaHeight.js │ │ └── inputNumeric.js │ ├── isUserConfirm.js │ ├── maximizeOverlay.js │ └── revertMaximizeOverlay.js │ ├── configurationScheme.json │ ├── createEditor.js │ ├── css │ ├── images │ │ ├── btn_adjust_lineheight_16.png │ │ ├── btn_auto_adjust_lineheight_16.png │ │ ├── btn_auto_replicate_16.png │ │ ├── btn_block_edit_mode_16.png │ │ ├── btn_boundary_detection_16.png │ │ ├── btn_copy_16.png │ │ ├── btn_create_span_by_touch_16.png │ │ ├── btn_cut_16.png │ │ ├── btn_delete_16.png │ │ ├── btn_edit_properties_16.png │ │ ├── btn_edit_text_by_touch_16.png │ │ ├── btn_expand_span_by_touch_16.png │ │ ├── btn_help_16.png │ │ ├── btn_import_16.png │ │ ├── btn_new_entity_16.png │ │ ├── btn_pallet_16.png │ │ ├── btn_pallet_modified_16.png │ │ ├── btn_paste_16.png │ │ ├── btn_redo_16.png │ │ ├── btn_relation_edit_mode_16.png │ │ ├── btn_replicate_span_annotation_16.png │ │ ├── btn_setting_16.png │ │ ├── btn_shrink_span_by_touch_16.png │ │ ├── btn_simple_view_16.png │ │ ├── btn_term_edit_mode_16.png │ │ ├── btn_text_edit_mode_16.png │ │ ├── btn_undo_16.png │ │ ├── btn_upload_16.png │ │ ├── btn_upload_automatically_16.png │ │ ├── btn_upload_modified_16.png │ │ ├── btn_view_mode_16.png │ │ ├── keyhelp.png │ │ ├── keyhelp.psd │ │ ├── link.png │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ ├── ui-icons_222222_256x240.png │ │ ├── ui-icons_228ef1_256x240.png │ │ ├── ui-icons_ef8c08_256x240.png │ │ ├── ui-icons_ffd27a_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ ├── modules │ │ └── jquery-ui.min.less │ ├── textae-const.less │ ├── textae-control.less │ ├── textae-editor-dialog-autocomplete.less │ ├── textae-editor-dialog.less │ ├── textae-editor-entity.less │ ├── textae-editor-fontawsome.less │ ├── textae-editor-pallet.less │ ├── textae-editor.less │ ├── textae-text-edit-dialog.less │ └── textae.less │ ├── exceptions │ └── FormatConversionError.js │ ├── isAbleToParseFloat.js │ ├── isJSON.js │ ├── isURI.js │ ├── openEditNumericAttributeDialog.js │ ├── openEditStringAttributeDialog.js │ └── textae │ ├── API.js │ ├── Tool │ ├── EditorContainer │ │ ├── index.js │ │ └── isTextFields.js │ ├── Veil.js │ ├── getMousePoint.js │ ├── index.js │ └── observeBodyEvents.js │ ├── index.js │ └── toEditor.js ├── tmp └── .keep ├── userAcceptanceTest ├── 20210716_02.md ├── 20210720_01.md ├── 20210720_02_mouse.md ├── 20210720_03.md ├── 20210720_04.md ├── 20210720_06.md ├── 20210727_02.md ├── 20210727_03.md ├── 20210728_01.md ├── 20210730_01.md ├── 20210803_01.md ├── 20210803_02.md ├── 20210804_01.md ├── 20210805_01.md ├── 20210805_02.md ├── 20210805_03.md ├── 20210805_04.md ├── 20210805_05_keyboard.md ├── 20210806_01.md ├── 20210806_02.md ├── 20210806_03.md ├── 20210806_04.md ├── 20210810_01.md ├── 20210811_01.md ├── 20210812_02.md ├── 20210813_01.md ├── 20210816_01.md ├── 20210817_01.md ├── 20210817_02.md ├── 20210818_01.md ├── 20210819_01.md ├── 20210820_01.md ├── 20210824_01.md ├── 20210825_01.md ├── 20210825_02.md ├── 20210826_01.md ├── 20210826_02.md ├── 20210827_01.md ├── 20210827_02.md ├── 20210831_01.md ├── 20210901_01.md ├── 20210901_02.md ├── 20210902_01.md ├── 20210902_02.md ├── 20210902_03.md ├── 20210902_04.md ├── 20210902_05.md ├── 20210907_01.md ├── 20210907_02.md ├── 20210908_01.md ├── 20210908_02.md ├── 20210914_01.md ├── 20210914_02.md ├── 20210921_01.md ├── 20210921_02.md ├── 20210922_01.md ├── 20210922_02.md ├── 20210922_03.md ├── 20210928_01.md ├── 20210929_01.md ├── 20210929_02.md ├── 20210929_03.md ├── 20210929_04.md ├── 20210930_01.md ├── 20210930_02.md ├── 20210930_03.md ├── 20210930_04.md ├── 20210930_05.md ├── 20211028_01.md ├── 20211028_02.md ├── 20211029_01.md ├── 20211102_01.md ├── 20211102_02.md ├── 20211102_03.md ├── 20211102_04.md ├── 20211104_01.md ├── 20211105_01.md ├── 20211109_01.md ├── 20211109_02.md ├── 20211109_03.md ├── 20211109_04.md ├── 20211109_05.md ├── 20211109_06.md ├── 20211110_01.md ├── 20211110_02.md ├── 20211110_03.md ├── 20211110_04.md ├── 20211110_05.md ├── 20211116_01.md ├── 20211116_02.md ├── 20211117_01.md ├── 20211117_02.md ├── 20211118_01.md ├── 20211118_02.md ├── 20211118_03.md ├── 20211118_04.md ├── 20211124_01.md ├── 20211124_02.md ├── 20211124_03.md ├── 20211124_04.md ├── 20211125_01.md ├── 20211125_02.md ├── 20211130_01.md ├── 20211201_01.md ├── 20211207_01.md ├── 20211207_02.md ├── 20211207_03.md ├── 20211207_04.md ├── 20211207_05.md ├── 20211207_06.md ├── 20211207_07.md ├── 20211208_01.md ├── 20211208_02.md ├── 20211208_03.md ├── 20211208_04.md ├── 20211208_05.md ├── 20211208_06.md ├── 20211208_07.md ├── 20211208_08.md ├── 20211208_09.md ├── 20211208_10.md ├── 20211209_01.md ├── 20211209_02.md ├── 20211209_03.md ├── 20211214_01.md ├── 20211215_01.md ├── 20211215_02.md ├── 20211215_03.md ├── 20211215_04.md ├── 20211215_05.md ├── 20211215_06.md ├── 20211215_07.md ├── 20211216_01.md ├── 20211221_01.md ├── 20211222_01.md ├── 20211223_01.md ├── 20211224_01.md ├── 20211224_02.md ├── 20211224_03.md ├── 20211224_04.md ├── 20220105_01.md ├── 20220105_02.md ├── 20220105_03.md ├── 20220106_01.md ├── 20220106_02.md ├── 20220106_03.md ├── 20220106_04.md ├── 20220106_05.md ├── 20220106_06.md ├── 20220106_07.md ├── 20220108_02.md ├── 20220112_01.md ├── 20220112_02.md ├── 20220112_03.md ├── 20220112_04.md ├── 20220112_05.md ├── 20220112_06.md ├── 20220112_07.md ├── 20220113_01.md ├── 20220113_02.md ├── 20220113_03.md ├── 20220118_01.md ├── 20220118_02.md ├── 20220118_03.md ├── 20220119_01.md ├── 20220119_02.md ├── 20220119_03.md ├── 20220119_04.md ├── 20220119_05.md ├── 20220119_06.md ├── 20220120_01.md ├── 20220121_01.md ├── 20220121_02.md ├── 20220121_03.md ├── 20220121_04.md ├── 20220125_01.md ├── 20220125_02.md ├── 20220125_03.md ├── 20220127_01.md ├── 20220127_02.md ├── 20220127_03.md ├── 20220127_04.md ├── 20220202_01.md ├── 20220202_02.md ├── 20220202_03.md ├── 20220202_04.md ├── 20220202_05.md ├── 20220203_01.md ├── 20220203_02.md ├── 20220207_01.md ├── 20220207_02.md ├── 20220207_03.md ├── 20220207_04.md ├── 20220208_01.md ├── 20220208_03.md ├── 20220210_01.md ├── 20220210_02.md ├── 20220215_01.md ├── 20220215_02.md ├── 20220215_03.md ├── 20220215_04.md ├── 20220215_05.md ├── 20220216_01.md ├── 20220216_02.md ├── 20220216_03.md ├── 20220216_04.md ├── 20220216_05.md ├── 20220217_01.md ├── 20220217_02.md ├── 20220222_01_mouse.md ├── 20220222_02_mouse.md ├── 20220222_03_mouse.md ├── 20220222_04_mouse.md ├── 20220302_01.md ├── 20220302_02.md ├── 20220302_03.md ├── 20220302_04.md ├── 20220302_05.md ├── 20220302_06.md ├── 20220302_07.md ├── 20220302_08.md ├── 20220303_01_mouse.md ├── 20220303_02_mouse.md ├── 20220304_01.md ├── 20220304_02.md ├── 20220308_01.md ├── 20220308_02.md ├── 20220308_03.md ├── 20220309_01_mouse.md ├── 20220309_02_keyboard.md ├── 20220309_03_monuse.md ├── 20220309_04_keyboard.md ├── 20220309_05_keyborard.md ├── 20220310_01.md ├── 20220310_02.md ├── 20220314_01.md ├── 20220315_01_mouse.md ├── 20220315_02_keyboard.md ├── 20220315_03_keyboard.md ├── 20220318_01.md ├── 20220318_02.md ├── 20220318_03.md ├── 20220318_04.md ├── 20220318_05.md ├── 20220318_06.md ├── 20220407_01.md ├── 20220407_01_mouse.md ├── 20220412_01.md ├── 20220412_02.md ├── 20220413_01_mouse.md ├── 20220415_01.md ├── 20220415_02.md ├── 20220415_03.md ├── 20220419_01.md ├── 20220419_02.md ├── 20220503_01_firefox.md ├── 20220503_02.md ├── 20220506_01.md ├── choice_test_devices.rb ├── rareUserAcceptanceTest.md ├── todoTest.md └── userAcceptanceTest.md ├── webpack.dev.mjs └── webpack.prod.mjs /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and Dist 2 | 3 | on: 4 | push: 5 | branches: 6 | - stable/4 7 | pull_request: 8 | branches: 9 | - stable/4 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '22' 23 | 24 | - name: Install dependencies 25 | run: npm install 26 | 27 | - name: Run dist:build 28 | run: npm run dist:build 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | *.dev_data.json 4 | src/lib/fonts/ 5 | src/lib/css/textae.css 6 | dev/bundle.js 7 | /tmp/* 8 | !/tmp/.keep 9 | textae-*.tgz 10 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | npx lint-staged 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/lib/modules/jquery.jsPlumb-1.5.5-min.js 2 | src/lib/modules/jquery.jsPlumb-1.5.5.js 3 | dist/lib/textae-*.min.js -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "semi": false, 4 | "singleQuote": true, 5 | "arrowParens": "always" 6 | } 7 | -------------------------------------------------------------------------------- /.versionrc: -------------------------------------------------------------------------------- 1 | { 2 | "types": [ 3 | {"type": "feature", "section": "Features"}, 4 | {"type": "fix", "section": "Bug Fixes"}, 5 | {"type": "refactor", "hidden": true}, 6 | {"type": "chore", "hidden": true}, 7 | {"type": "misc", "hidden": true}, 8 | {"type": "test", "hidden": true} 9 | ] 10 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "alertifyjs", 4 | "colspan", 5 | "delgate", 6 | "dohtml", 7 | "eskape", 8 | "jsondiffpatch", 9 | "lifesciencedb", 10 | "observ", 11 | "rowspan", 12 | "textae" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /dev/2_annotations.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Downregulation is the process by which a cell decreases the quantity of a cellular component, such as RNA or protein, in response to an external variable. An increase of a cellular component is called upregulation." 3 | } 4 | -------------------------------------------------------------------------------- /dev/attributes_with_no_required_properties_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "attribute types": [ 3 | { 4 | "pred": "category", 5 | "value type": "string" 6 | }, 7 | { 8 | "pred": "tags", 9 | "value type": "selection" 10 | }, 11 | { 12 | "pred": "rate", 13 | "value type": "numeric" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /dev/dummy_auth_page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | This is a dummy auth page! 4 | 5 | -------------------------------------------------------------------------------- /dev/elon.md: -------------------------------------------------------------------------------- 1 | [Elon Musk][Person] is a member of the [PayPal Mafia][Organization]. 2 | 3 | [Person]: https://example.com/Person 4 | [Organization]: https://example.com/Organization 5 | -------------------------------------------------------------------------------- /dev/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dev/favicon.ico -------------------------------------------------------------------------------- /dev/for_import.txt: -------------------------------------------------------------------------------- 1 | This file is a text file. -------------------------------------------------------------------------------- /dev/invalid_attributes_annotation.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "attribute types": [ 4 | { 5 | "pred": "rate", 6 | "value type": "numeric" 7 | } 8 | ] 9 | }, 10 | "text": "dummy string" 11 | } 12 | -------------------------------------------------------------------------------- /dev/invalid_color_annotation.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "attribute types": [ 4 | { 5 | "pred": "bad color", 6 | "value type": "selection", 7 | "values": [ 8 | { 9 | "color": "Invalid color format", 10 | "id": "id" 11 | } 12 | ] 13 | } 14 | ] 15 | }, 16 | "text": "dummy string" 17 | } 18 | -------------------------------------------------------------------------------- /dev/invalid_color_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "attribute types": [ 3 | { 4 | "pred": "bad color", 5 | "value type": "selection", 6 | "values": [ 7 | { 8 | "color": "Invalid color format", 9 | "id": "id" 10 | } 11 | ] 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /dev/outer.css: -------------------------------------------------------------------------------- 1 | /* Emulate an outer css file */ 2 | p { 3 | line-height:1.5em; 4 | } -------------------------------------------------------------------------------- /dev/target.txt: -------------------------------------------------------------------------------- 1 | An annotation is a metadatum (e.g. a post, explanation, markup) attached to location or other data. 2 | -------------------------------------------------------------------------------- /dev/warning_not_integer_span.json: -------------------------------------------------------------------------------- 1 | { 2 | "text": "Ribonucleic acid (RNA) is a ubiquitous family of large biological molecules.", 3 | "denotations": [ 4 | { 5 | "id": "E1", 6 | "span": { 7 | "begin": "0", 8 | "end": 16 9 | }, 10 | "obj": "リボ核酸" 11 | }, 12 | { 13 | "id": "E2", 14 | "span": { 15 | "begin": 49.5, 16 | "end": 75 17 | }, 18 | "obj": "大きな生体分子" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /dist/demo/bionlp-st-ge/demo-cdn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dist/demo/bionlp-st-ge/demo-empty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dist/demo/bionlp-st-ge/demo-local.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dist/lib/css/images/btn_adjust_lineheight_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_adjust_lineheight_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_auto_adjust_lineheight_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_auto_adjust_lineheight_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_auto_replicate_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_auto_replicate_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_block_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_block_edit_mode_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_boundary_detection_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_boundary_detection_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_copy_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_copy_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_create_span_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_create_span_by_touch_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_cut_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_cut_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_delete_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_delete_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_edit_properties_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_edit_properties_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_edit_text_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_edit_text_by_touch_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_expand_span_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_expand_span_by_touch_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_help_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_help_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_import_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_import_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_new_entity_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_new_entity_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_pallet_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_pallet_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_pallet_modified_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_pallet_modified_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_paste_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_paste_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_redo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_redo_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_relation_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_relation_edit_mode_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_replicate_span_annotation_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_replicate_span_annotation_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_setting_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_setting_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_shrink_span_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_shrink_span_by_touch_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_simple_view_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_simple_view_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_term_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_term_edit_mode_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_text_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_text_edit_mode_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_undo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_undo_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_upload_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_upload_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_upload_automatically_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_upload_automatically_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_upload_modified_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_upload_modified_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/btn_view_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/btn_view_mode_16.png -------------------------------------------------------------------------------- /dist/lib/css/images/keyhelp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/keyhelp.png -------------------------------------------------------------------------------- /dist/lib/css/images/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/link.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /dist/lib/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /dist/lib/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /dist/lib/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /dist/lib/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /dist/lib/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /dist/lib/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/dist/lib/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /src/demo/bionlp-st-ge/demo-cdn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/demo/bionlp-st-ge/demo-empty.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/demo/bionlp-st-ge/demo-local.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import textae from './lib/textae' 2 | import packageJson from '../package.json' 3 | 4 | document.addEventListener('DOMContentLoaded', textae) 5 | 6 | // This function is experimental. 7 | // It is being released to verify its feasibility for integration into React. 8 | window.initializeTextAEEditor = textae 9 | 10 | console.log(`TextAE Version ${packageJson.version} loaded.`) 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/getAllSpansIn.js: -------------------------------------------------------------------------------- 1 | export default function (track) { 2 | const { typesettings, denotations, blocks } = track 3 | return (typesettings || []).concat(denotations || []).concat(blocks || []) 4 | } 5 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/getAllSpansOf.js: -------------------------------------------------------------------------------- 1 | // The boundaries of elements in the typesetings and 2 | // the denotations and blocks cannot cross each other. 3 | 4 | import getAllSpansIn from './getAllSpansIn' 5 | 6 | // The same is true when across the tracks. 7 | export default function (rowData) { 8 | let spans = getAllSpansIn(rowData) 9 | 10 | if (rowData.tracks) { 11 | for (const track of rowData.tracks) { 12 | spans = spans.concat(getAllSpansIn(track)) 13 | } 14 | } 15 | 16 | return spans 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/ChainValidation/setSourceProperty.js: -------------------------------------------------------------------------------- 1 | export default function (n, name) { 2 | n.sourceProperty = name 3 | return n 4 | } 5 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/debugLogCrossing.js: -------------------------------------------------------------------------------- 1 | export default function (name, errors) { 2 | for (const [key, values] of errors.getInhibitors('isNotCrossing')) { 3 | console.warn( 4 | `Crossing ${name}: [${key.span.begin}:${key.span.end}](${ 5 | key.id 6 | }) crosses with ${values 7 | .map(({ id, span }) => `[${span.begin}:${span.end}](${id})`) 8 | .join(', ')}` 9 | ) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/getSpanValidation/isBeginAndEndIn/index.js: -------------------------------------------------------------------------------- 1 | import isInText from './isInText' 2 | 3 | export default function (text, span) { 4 | return isInText(span.begin, text) && isInText(span.end, text) 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/getSpanValidation/isBeginAndEndIn/isInText.js: -------------------------------------------------------------------------------- 1 | export default function (boundary, text) { 2 | return 0 <= boundary && boundary <= text.length 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/isContains.js: -------------------------------------------------------------------------------- 1 | export default function (dictionary, referedEntityId) { 2 | return dictionary.some((entry) => entry.id === referedEntityId) 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/isIDUnique.js: -------------------------------------------------------------------------------- 1 | export default function (spans, node) { 2 | // Span without ID is acceptable. 3 | return ( 4 | node.id === undefined || 5 | spans.filter((d) => node.id && node.id === d.id).length === 1 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/validateAttribute/index.js: -------------------------------------------------------------------------------- 1 | import isContains from '../isContains' 2 | import ChainValidation from '../ChainValidation' 3 | import isUniqueIn from './isUniqueIn' 4 | 5 | export default function (subjects, attributes) { 6 | return new ChainValidation(attributes) 7 | .and('subject', (a) => isContains(subjects, a.subj)) 8 | .and('unique', (node) => isUniqueIn(attributes, node)) 9 | .validateAll() 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/validateAttribute/isUniqueIn.js: -------------------------------------------------------------------------------- 1 | export default function (attributes, node) { 2 | return ( 3 | attributes.filter( 4 | (a) => a.subj === node.subj && a.pred === node.pred && a.obj === node.obj 5 | ).length === 1 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/validateDenotation.js: -------------------------------------------------------------------------------- 1 | import getSpanValidation from './getSpanValidation' 2 | import isIDUnique from './isIDUnique' 3 | 4 | export default function (text, denotations, spanOfAllTracks, spansInTrack) { 5 | return getSpanValidation(denotations, text, spanOfAllTracks, 'denotations') 6 | .and('uniqueID', (n) => isIDUnique(spansInTrack, n)) 7 | .validateAll() 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/validateRelation.js: -------------------------------------------------------------------------------- 1 | import isContains from './isContains' 2 | import ChainValidation from './ChainValidation' 3 | 4 | export default function (denotations, relations) { 5 | return new ChainValidation(relations) 6 | .and('object', (r) => isContains(denotations, r.obj)) 7 | .and('subject', (r) => isContains(denotations, r.subj)) 8 | .validateAll() 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/AnnotationEvaluator/validateAnnotation/validateTypeSettings.js: -------------------------------------------------------------------------------- 1 | import getSpanValidation from './getSpanValidation' 2 | 3 | export default function (text, targetSpans, allSpans) { 4 | return getSpanValidation( 5 | targetSpans, 6 | text, 7 | allSpans, 8 | 'typesettings' 9 | ).validateAll() 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/DefinedTypeContainer/getForwardMatchID/getForwardMatchTypes.js: -------------------------------------------------------------------------------- 1 | export default function getForwardMatchTypes(typeIds, id) { 2 | const forwardMatchTypes = [] 3 | 4 | for (const definedType of typeIds) { 5 | if ( 6 | definedType.indexOf('*') !== -1 && 7 | id.indexOf(definedType.slice(0, -1)) === 0 8 | ) { 9 | forwardMatchTypes.push(definedType) 10 | } 11 | } 12 | 13 | return forwardMatchTypes 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/DefinedTypeContainer/getForwardMatchID/getLongestIdMatchType.js: -------------------------------------------------------------------------------- 1 | export default function getLongestIdMatchType(typeIds) { 2 | let longestMatchId = '' 3 | 4 | for (const id of typeIds) { 5 | if (id.length > longestMatchId.length) { 6 | longestMatchId = id 7 | } 8 | } 9 | 10 | return longestMatchId 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/DefinedTypeContainer/getForwardMatchID/index.js: -------------------------------------------------------------------------------- 1 | import getForwardMatchTypes from './getForwardMatchTypes' 2 | import getLongestIdMatchType from './getLongestIdMatchType' 3 | 4 | export default function getForwardMatchID(typeIds, id) { 5 | // '*' at the last char of id means wildcard. 6 | const forwardMatchTypes = getForwardMatchTypes(typeIds, id) 7 | 8 | if (forwardMatchTypes.length === 0) { 9 | return null 10 | } 11 | 12 | // If some wildcard-id are matched, return the id of the most longest matched. 13 | return getLongestIdMatchType(forwardMatchTypes) 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/countUsage.js: -------------------------------------------------------------------------------- 1 | export default function countUsage(map, instances) { 2 | for (const [key, value] of map.entries()) { 3 | map.set(key, { ...value, usage: 0 }) 4 | } 5 | 6 | return instances.reduce((countMap, { typeName }) => { 7 | countMap.get(typeName).usage += 1 8 | 9 | return countMap 10 | }, map) 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/formatForPallet/createTypesWithoutInstance.js: -------------------------------------------------------------------------------- 1 | export default function (defindTypeNames, countMap) { 2 | const typesWithoutInstance = [] 3 | for (const type of defindTypeNames) { 4 | if (!countMap.has(type)) { 5 | typesWithoutInstance.push(type) 6 | } 7 | } 8 | 9 | // Sort by name 10 | typesWithoutInstance.sort((a, b) => { 11 | return a > b ? 1 : a < b ? -1 : 0 12 | }) 13 | 14 | return typesWithoutInstance 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/formatForPallet/index.js: -------------------------------------------------------------------------------- 1 | import getUrlMatches from '../../../getUrlMatches' 2 | 3 | export default function formatForPallet( 4 | types, 5 | countMap, 6 | definedTypes, 7 | defaultType, 8 | defaultColor 9 | ) { 10 | return types.map((id) => ({ 11 | id, 12 | label: definedTypes.getLabelOf(id) || undefined, 13 | defaultType: id === defaultType, 14 | uri: getUrlMatches(id) ? id : undefined, 15 | color: definedTypes.getColorOf(id) || defaultColor, 16 | useNumber: countMap.get(id).usage 17 | })) 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/DefinitionContainer/sortByCountAndName.js: -------------------------------------------------------------------------------- 1 | export default function (countTypeUse) { 2 | // Sort by number of types, and by name if numbers are same. 3 | const typeNames = Array.from(countTypeUse.keys()) 4 | 5 | typeNames.sort((a, b) => { 6 | const diff = countTypeUse.get(b).usage - countTypeUse.get(a).usage 7 | return diff !== 0 ? diff : a > b ? 1 : a < b ? -1 : 0 8 | }) 9 | 10 | return typeNames 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/InstanceContainer/isFunction.js: -------------------------------------------------------------------------------- 1 | // see: https://stackoverflow.com/questions/5999998/check-if-a-variable-is-of-function-type 2 | export default function isFunction(functionToCheck) { 3 | return ( 4 | functionToCheck && {}.toString.call(functionToCheck) === '[object Function]' 5 | ) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/CurveAlgorithmFactory/ArchedCurveAlgorithm.js: -------------------------------------------------------------------------------- 1 | import CurveAlgorithm from './CurveAlgorithm' 2 | 3 | export default class ArchedCurveAlgorithm extends CurveAlgorithm { 4 | get isSourceJettyVisible() { 5 | return true 6 | } 7 | 8 | get isTargetJettyVisible() { 9 | return true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/MarkerHeight.js: -------------------------------------------------------------------------------- 1 | export const MarkerHeight = 6 2 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/createJetty.js: -------------------------------------------------------------------------------- 1 | import { NS } from '../NS' 2 | import moveJetty from './moveJetty' 3 | 4 | export default function (x, y, entity) { 5 | const jetty = document.createElementNS(NS.SVG, 'polyline') 6 | 7 | moveJetty(jetty, x, y, entity) 8 | 9 | return jetty 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/createPath.js: -------------------------------------------------------------------------------- 1 | import { NS } from '../NS' 2 | 3 | /** 4 | * 5 | * @returns {SVGGraphicsElement} path 6 | */ 7 | export default function () { 8 | const path = document.createElementNS(NS.SVG, 'path') 9 | path.classList.add('textae-editor__relation') 10 | return path 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/createSourceBollard.js: -------------------------------------------------------------------------------- 1 | import { NS } from '../NS' 2 | import { MarkerHeight } from './MarkerHeight' 3 | 4 | export default function () { 5 | const bollard = document.createElementNS(NS.SVG, 'polygon') 6 | bollard.setAttribute('points', `-4 ${MarkerHeight}, 4 ${MarkerHeight}, 0 0`) 7 | 8 | return bollard 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/createTargetBollard.js: -------------------------------------------------------------------------------- 1 | import { NS } from '../NS' 2 | import { MarkerHeight } from './MarkerHeight' 3 | 4 | export default function () { 5 | const bollard = document.createElementNS(NS.SVG, 'polygon') 6 | bollard.setAttribute('points', `-4 0, 4 0, 0 ${MarkerHeight}`) 7 | 8 | return bollard 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/moveJetty.js: -------------------------------------------------------------------------------- 1 | import { MarkerHeight } from './MarkerHeight' 2 | 3 | /** 4 | * 5 | * @param {Element} jetty 6 | * @param {number} x 7 | * @param {number} y 8 | * @param {import('../../../../../EntityInstance').default} entity 9 | */ 10 | export default function (jetty, x, y, entity) { 11 | jetty.setAttribute( 12 | 'points', 13 | `${x} ${y + MarkerHeight}, ${entity.offsetCenter} ${y + MarkerHeight}, ${ 14 | entity.offsetCenter 15 | } ${entity.offsetTop}` 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/Arrow/updatePath.js: -------------------------------------------------------------------------------- 1 | export default function (path, curveAlgorithm, color, isBold) { 2 | path.setAttribute('d', curveAlgorithm.pathCommands) 3 | 4 | path.setAttribute('style', `stroke: ${color};`) 5 | 6 | if (isBold) { 7 | path.classList.add('textae-editor__relation--isBold') 8 | } else { 9 | path.classList.remove('textae-editor__relation--isBold') 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/NS.js: -------------------------------------------------------------------------------- 1 | export const NS = { 2 | SVG: 'http://www.w3.org/2000/svg' 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/toDisplayName/getDisplayNameTag.js: -------------------------------------------------------------------------------- 1 | import getDisplayName from '../../../../getDisplayName' 2 | import getURI from '../../../../getURI' 3 | import anemone from '../../../../../component/anemone' 4 | 5 | export default function (namespace, definitionContainer, value) { 6 | const displayName = getDisplayName( 7 | namespace, 8 | value, 9 | definitionContainer.getLabel(value) 10 | ) 11 | const href = getURI(namespace, value, definitionContainer.getURI(value)) 12 | return href 13 | ? anemone`${displayName}` 14 | : anemone`${displayName}` 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/RelationInstanceContainer/RelationInstance/toDisplayName/index.js: -------------------------------------------------------------------------------- 1 | import getDisplayNameTag from './getDisplayNameTag' 2 | 3 | export default function toDisplayName( 4 | relation, 5 | namespace, 6 | definitionContainer 7 | ) { 8 | return `[${relation.id}] ${getDisplayNameTag( 9 | namespace, 10 | definitionContainer, 11 | relation.typeName 12 | )}` 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/BlockSpanInstance/renderBackground.js: -------------------------------------------------------------------------------- 1 | import dohtml from 'dohtml' 2 | 3 | export default function (parentElement, id) { 4 | const div = dohtml.create(` 5 |
6 | `) 7 | 8 | // Always add to the top of the annotation box to place it behind the grid. 9 | parentElement.insertAdjacentElement('afterbegin', div) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/BlockSpanInstance/setPosition.js: -------------------------------------------------------------------------------- 1 | export default function (element, top, left, width, height) { 2 | element.style.top = `${top}px` 3 | element.style.left = `${left}px` 4 | element.style.width = `${width}px` 5 | element.style.height = `${height}px` 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/SELECTED.js: -------------------------------------------------------------------------------- 1 | const SELECTED = 'ui-selected' 2 | export default SELECTED 3 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/SpanInstance/createGridHtml.js: -------------------------------------------------------------------------------- 1 | export default function (spanId, top, left, width) { 2 | return ` 3 |
7 |
8 | ` 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/SpanInstance/getRightGrid.js: -------------------------------------------------------------------------------- 1 | import getRightSpanElement from '../../../getRightSpanElement' 2 | 3 | export default function (editorHTMLElement, spanId) { 4 | const rightSpan = getRightSpanElement(editorHTMLElement, spanId) 5 | 6 | if (rightSpan) { 7 | return document.querySelector(`#G${rightSpan.id}`) 8 | } 9 | 10 | return null 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/SpanInstance/updateGridPosition/index.js: -------------------------------------------------------------------------------- 1 | import isStaying from './isStaying' 2 | 3 | export default function (gridElement, top, left) { 4 | if (!isStaying(gridElement, top, left)) { 5 | gridElement.style.top = `${top}px` 6 | gridElement.style.left = `${left}px` 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/SpanInstance/updateGridPosition/isStaying.js: -------------------------------------------------------------------------------- 1 | export default function (gridElement, top, left) { 2 | if ( 3 | gridElement.style && 4 | parseFloat(gridElement.style.top) === top && 5 | parseFloat(gridElement.style.left) === left 6 | ) { 7 | return true 8 | } 9 | return false 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/TextSelection/getOffsetFromParent.js: -------------------------------------------------------------------------------- 1 | export default function (node) { 2 | let offset = 0 3 | 4 | for (const prevNode of node.parentElement.childNodes) { 5 | // until the focus node 6 | if (prevNode == node) { 7 | break 8 | } 9 | 10 | if (prevNode.nodeName === '#text') { 11 | offset += prevNode.nodeValue.length 12 | } else { 13 | offset += prevNode.textContent.length 14 | } 15 | } 16 | 17 | return offset 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/createRangeToSpan/createRange.js: -------------------------------------------------------------------------------- 1 | export default function (textNode, start, end) { 2 | const range = document.createRange() 3 | 4 | range.setStart(textNode, start) 5 | range.setEnd(textNode, end) 6 | 7 | return range 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/createRangeToSpan/getRenderingPosition/getOffset.js: -------------------------------------------------------------------------------- 1 | export default function (span, startOfTextNode) { 2 | const start = span.begin - startOfTextNode 3 | const end = span.end - startOfTextNode 4 | 5 | return { 6 | start, 7 | end 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/createRangeToSpan/getRenderingPosition/getRenderingPositionFromParent.js: -------------------------------------------------------------------------------- 1 | import getOffset from './getOffset' 2 | 3 | export default function (span) { 4 | const { start, end } = getOffset(span, span.parent.begin) 5 | 6 | return { 7 | textNode: span.parent.element.firstChild, 8 | start, 9 | end 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/getCurrentMaxHeight.js: -------------------------------------------------------------------------------- 1 | export default function (spans) { 2 | const maxHeight = Math.max( 3 | ...spans.map((span) => span.heightIncludeDescendantGrids) 4 | ) 5 | return maxHeight 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/spanComparator.js: -------------------------------------------------------------------------------- 1 | export default function (a, b) { 2 | return a.begin - b.begin || b.end - a.end 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/updateSpanTree/getParent/index.js: -------------------------------------------------------------------------------- 1 | import isChildOf from './isChildOf' 2 | 3 | export default function getParet(span, parent) { 4 | if (isChildOf(span, parent)) { 5 | return parent 6 | } else if (parent.parent) { 7 | return getParet(span, parent.parent) 8 | } else { 9 | return null 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/SpanInstanceContainer/updateSpanTree/getParent/isChildOf.js: -------------------------------------------------------------------------------- 1 | export default function (span, maybeParent) { 2 | if (!maybeParent) { 3 | return false 4 | } 5 | 6 | return maybeParent.begin <= span.begin && span.end <= maybeParent.end 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/createTextBox/TextBox/getLineHeight.js: -------------------------------------------------------------------------------- 1 | import pixelToInt from './pixelToInt' 2 | 3 | export default function (textBox) { 4 | const style = window.getComputedStyle(textBox) 5 | return pixelToInt(style.lineHeight) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/createTextBox/TextBox/pixelToInt.js: -------------------------------------------------------------------------------- 1 | export default function (str) { 2 | // The default value of google chrome line-height is "normal". 3 | // "normal" cannot be converted to an integer. 4 | const i = parseInt(str, 10) 5 | return isNaN(i) ? 0 : i 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/createTextBox/TextBox/setLineHeight.js: -------------------------------------------------------------------------------- 1 | export default function (textBox, heightValue, additionalPaddingTop) { 2 | textBox.style.lineHeight = `${heightValue}px` 3 | textBox.style.paddingTop = `${heightValue / 2 + additionalPaddingTop}px` 4 | } 5 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/createTextBox/TextBox/updateTextBoxHeight.js: -------------------------------------------------------------------------------- 1 | import pixelToInt from './pixelToInt' 2 | 3 | // Reduce the space under the .textae-editor__text-box same as padding-top. 4 | export default function (textBox, additionalPaddingTop) { 5 | const style = window.getComputedStyle(textBox) 6 | 7 | // The height calculated by auto is exclude the value of the padding top. 8 | // Rest small space. 9 | textBox.style.height = 'auto' 10 | textBox.style.height = `${ 11 | textBox.offsetHeight - 12 | pixelToInt(style.paddingTop) + 13 | 20 + 14 | additionalPaddingTop 15 | }px` 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/getAnnotationBox.js: -------------------------------------------------------------------------------- 1 | // Get the display area for denotations and relations. 2 | export default function (editorHTMLElement) { 3 | return editorHTMLElement.querySelector('.textae-editor__annotation-box') 4 | } 5 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/getBoundaryCrossingSpans.js: -------------------------------------------------------------------------------- 1 | import isBoundaryCrossing from '../isBoundaryCrossing' 2 | 3 | export default function (spans, begin, end) { 4 | return spans.filter(({ span }) => isBoundaryCrossing(begin, end, span)) 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/getReplicationRanges/getDuplicateSentenceFromText.js: -------------------------------------------------------------------------------- 1 | export default function (text, beginOfSentence, endOfSentence) { 2 | const searchSentence = text.substring(beginOfSentence, endOfSentence) 3 | const sentenceLength = endOfSentence - beginOfSentence 4 | const findRanges = [] 5 | 6 | let end = 0 7 | 8 | for ( 9 | let begin = text.indexOf(searchSentence); 10 | begin !== -1; 11 | begin = text.indexOf(searchSentence, end) 12 | ) { 13 | end = begin + sentenceLength 14 | 15 | findRanges.push({ 16 | begin, 17 | end 18 | }) 19 | } 20 | 21 | return findRanges 22 | } 23 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/getReplicationRanges/isWord.js: -------------------------------------------------------------------------------- 1 | // The preceding character and the following of a word character are delimiter. 2 | // For example, 't' ,a part of 'that', is not same with an origin span when it is 't'. 3 | export default function (sourceDoc, begin, end, isDelimiterFunc) { 4 | const precedingChar = sourceDoc.charAt(begin - 1) 5 | const followingChar = sourceDoc.charAt(end) 6 | 7 | return isDelimiterFunc(precedingChar) && isDelimiterFunc(followingChar) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/isBoundaryCrossingWithOtherSpans.js: -------------------------------------------------------------------------------- 1 | import getBoundaryCrossingSpans from './getBoundaryCrossingSpans' 2 | 3 | // A span its range is coross over with other spans are not able to rendered. 4 | // Because spans are renderd with span tag. Html tags can not be cross over. 5 | export default function (spans, begin, end) { 6 | console.assert(end !== undefined, 'end is necessary.') 7 | 8 | return ( 9 | getBoundaryCrossingSpans( 10 | spans.map((span) => ({ span })), 11 | begin, 12 | end 13 | ).length > 0 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/toBlocks.js: -------------------------------------------------------------------------------- 1 | export default function (annotationModel) { 2 | return annotationModel.entityInstanceContainer.blocks.map((entity) => ({ 3 | id: entity.id, 4 | span: { 5 | begin: entity.span.begin, 6 | end: entity.span.end 7 | }, 8 | obj: entity.typeName 9 | })) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/toDenotations.js: -------------------------------------------------------------------------------- 1 | export default function (annotationModel) { 2 | return annotationModel.entityInstanceContainer.denotations.map((entity) => ({ 3 | id: entity.id, 4 | span: { 5 | begin: entity.span.begin, 6 | end: entity.span.end 7 | }, 8 | obj: entity.typeName 9 | })) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/AnnotationModel/toRelations.js: -------------------------------------------------------------------------------- 1 | export default function (annotationModel) { 2 | return annotationModel.relationInstanceContainer.all.map((r) => { 3 | return { 4 | id: r.id, 5 | pred: r.typeName, 6 | subj: r.subj, 7 | obj: r.obj 8 | } 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/BrowserEventListener.js: -------------------------------------------------------------------------------- 1 | export default class BrowserEventListener { 2 | #target 3 | #event 4 | #listener 5 | 6 | constructor(target, event, listener) { 7 | this.#target = target 8 | this.#event = event 9 | this.#listener = listener 10 | 11 | this.#bind() 12 | } 13 | 14 | dispose() { 15 | this.#target.removeEventListener(this.#event, this.#listener) 16 | } 17 | 18 | #bind() { 19 | this.#target.addEventListener(this.#event, this.#listener) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/lib/Editor/EditorCSSClass.js: -------------------------------------------------------------------------------- 1 | export default class EditorCSSClass { 2 | constructor(editorHTMLElement) { 3 | this._editorHTMLElement = editorHTMLElement 4 | } 5 | startWait() { 6 | this._editorHTMLElement.classList.add('textae-editor--wait') 7 | } 8 | endWait() { 9 | this._editorHTMLElement.classList.remove('textae-editor--wait') 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/EditorEventListener.js: -------------------------------------------------------------------------------- 1 | export default class EditorEventListener { 2 | #eventEmitter 3 | #event 4 | #listener 5 | 6 | constructor(eventEmitter, event, listener) { 7 | this.#eventEmitter = eventEmitter 8 | this.#event = event 9 | this.#listener = listener 10 | 11 | eventEmitter.on(event, this.#listener) 12 | } 13 | 14 | dispose() { 15 | this.#eventEmitter.off(this.#event, this.#listener) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/Editor/RESOURCE_TYPE.js: -------------------------------------------------------------------------------- 1 | export const RESOURCE_TYPE = Object.freeze({ 2 | QUERY_PARAMETER: 'parameter', // The annotation data is passed as a query parameter. 3 | INLINE: 'inline', // The annotation data is written in the HTML. 4 | REMOTE_URL: 'remote', // The annotation data is set by remote URL. 5 | INSTANT: 'instant', // The annotation data is set by the data load dialog as json string. 6 | LOCAL_FILE: 'local file', // The annotation data is set by the data load dialog as a local file. 7 | UNKNOWN: 'unknown' 8 | }) 9 | -------------------------------------------------------------------------------- /src/lib/Editor/RemoteResource/AnnotationLoader/parseResponse/index.js: -------------------------------------------------------------------------------- 1 | import { isJsonResponse, isTxtResponse } from './responseTypes' 2 | import SimpleInlineTextAnnotation from '@pubann/simple-inline-text-annotation' 3 | 4 | export default async function parseResponse(response, url) { 5 | if (isJsonResponse(response, url)) { 6 | return await response.json() 7 | } else if (isTxtResponse(response, url)) { 8 | const inline_annotation = await response.text() 9 | return SimpleInlineTextAnnotation.parse(inline_annotation) 10 | } else { 11 | throw new Error('The content type of the loaded content is not supported.') 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/RemoteResource/AnnotationSaver/prepareRequestBody.js: -------------------------------------------------------------------------------- 1 | import SimpleInlineTextAnnotation from '@pubann/simple-inline-text-annotation' 2 | 3 | export default function prepareRequestBody(editedData, format) { 4 | if (format === 'json') { 5 | return JSON.stringify(editedData) 6 | } else if (format === 'inline') { 7 | return SimpleInlineTextAnnotation.generate(editedData) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/RemoteResource/AnnotationSaver/waitForPopUpClose.js: -------------------------------------------------------------------------------- 1 | // Watching for cross-domain pop-up windows to close. 2 | // https://stackoverflow.com/questions/9388380/capture-the-close-event-of-popup-window-in-javascript/48240128#48240128 3 | 4 | export default async function waitForPopUpClose(window) { 5 | return new Promise((resolve) => { 6 | const timer = setInterval(() => { 7 | if (window.closed) { 8 | clearInterval(timer) 9 | resolve() 10 | } 11 | }, 1000) 12 | }) 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/RemoteResource/openPopUp.js: -------------------------------------------------------------------------------- 1 | export default function (url) { 2 | const width = 600 3 | const height = 500 4 | 5 | return window.open(url, '_blank', `width=${width}, height=${height}`) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/AnnotationCommand.js: -------------------------------------------------------------------------------- 1 | import BaseCommand from './BaseCommand' 2 | 3 | export default class AnnotationCommand extends BaseCommand { 4 | get kind() { 5 | return new Set(['annotation_command']) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/BaseCommand.js: -------------------------------------------------------------------------------- 1 | export default class BaseCommand { 2 | get isEmpty() { 3 | return false 4 | } 5 | 6 | isExactly(kind) { 7 | return this.kind.has(kind) && this.kind.size === 1 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/ChangeTextAndMoveSpanCommand.js: -------------------------------------------------------------------------------- 1 | import ChangeTextCommand from './ChangeTextCommand' 2 | import CompositeCommand from './CompositeCommand' 3 | 4 | export default class ChangeTextAndMoveSpanCommand extends CompositeCommand { 5 | constructor(annotationModel, begin, end, newText) { 6 | super() 7 | 8 | this._isExecuteSubCommandsInReverseOrderWhenRevert = false 9 | 10 | this._subCommands = [ 11 | new ChangeTextCommand(annotationModel, { begin, end }, newText) 12 | ] 13 | 14 | this._logMessage = `change text from ${begin} to ${end} to ${newText}` 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/ConfigurationCommand.js: -------------------------------------------------------------------------------- 1 | import BaseCommand from './BaseCommand' 2 | 3 | export default class ConfigurationCommand extends BaseCommand { 4 | get kind() { 5 | return new Set(['configuration_command']) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/CreateEntityAndAttributesCommand/CreateAttributeToTheLatestEntityCommand.js: -------------------------------------------------------------------------------- 1 | import { CreateCommand } from '../commandTemplate' 2 | 3 | export default class CreateAttributeToTheLatestEntityCommand extends CreateCommand { 4 | constructor(annotationModel, obj, pred) { 5 | super(annotationModel, 'attribute', { 6 | obj, 7 | pred 8 | }) 9 | } 10 | 11 | execute() { 12 | const subj = this._annotationModel.entityInstanceContainer.all.pop().id 13 | this._instance.subj = subj 14 | return super.execute() 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/MoveEntitiesToSelectedDenotationSpanCommand/areAllEntitiesOfSpan.js: -------------------------------------------------------------------------------- 1 | export default function (span, entities) { 2 | return span.entities.every((entity) => entities.includes(entity)) 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/aggregateTargetEntities.js: -------------------------------------------------------------------------------- 1 | import aggregateTargetRelations from './aggregateTargetRelations' 2 | 3 | export default function ( 4 | targetEntities, 5 | targetRelations, 6 | targetAttributes, 7 | entity 8 | ) { 9 | targetEntities.add(entity) 10 | for (const attribute of entity.attributes) { 11 | targetAttributes.add(attribute) 12 | } 13 | for (const relation of entity.relations) { 14 | aggregateTargetRelations(targetRelations, targetAttributes, relation) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/aggregateTargetRelations.js: -------------------------------------------------------------------------------- 1 | export default function (targetRelations, targetAttributes, relation) { 2 | targetRelations.add(relation) 3 | for (const attribute of relation.attributes) { 4 | targetAttributes.add(attribute) 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/commandLog.js: -------------------------------------------------------------------------------- 1 | export default function (self, message, object) { 2 | // For debug 3 | if (object) { 4 | console.log(`[${self.constructor.name}]`, message, object) 5 | } else { 6 | console.log(`[${self.constructor.name}]`, message) 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/getCreateAttributeToItemsCommands.js: -------------------------------------------------------------------------------- 1 | import { CreateCommand } from './commandTemplate' 2 | 3 | export default function (annotationModel, items, pred, obj) { 4 | return items 5 | .filter((i) => !i.typeValues.hasSpecificPredicateAttribute(pred)) 6 | .map(({ id }) => { 7 | return new CreateCommand(annotationModel, 'attribute', { 8 | id: null, 9 | subj: id, 10 | pred, 11 | obj 12 | }) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Commander/Factory/getRemoveAttributesByPredCommands.js: -------------------------------------------------------------------------------- 1 | import { RemoveCommand } from './commandTemplate' 2 | 3 | export default function (annotationModel, items, pred) { 4 | return items 5 | .reduce((attrs, { attributes }) => attrs.concat(attributes), []) 6 | .filter((a) => a.pred === pred) 7 | .map((a) => new RemoveCommand(annotationModel, 'attribute', a)) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/backToDelimiter.js: -------------------------------------------------------------------------------- 1 | import skipCharacters from '../skipCharacters' 2 | import getPrev from './getPrev' 3 | 4 | export default function (str, position, isDelimiter) { 5 | return skipCharacters(getPrev, -1, str, position, (chars) => { 6 | // Proceed the position between two characters as (!delimiter delimiter) || (delimiter !delimiter) || (!delimiter !delimiter). 7 | return chars[1] && !isDelimiter(chars[0]) && !isDelimiter(chars[1]) 8 | }) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/backToWord.js: -------------------------------------------------------------------------------- 1 | import skipCharacters from '../skipCharacters' 2 | import getNext from './getNext' 3 | 4 | export default function (str, position, isWordEdge) { 5 | return skipCharacters(getNext, -1, str, position, isWordEdge) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/getNext.js: -------------------------------------------------------------------------------- 1 | export default function (str, position) { 2 | return [str.charAt(position), str.charAt(position + 1)] 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/getPrev.js: -------------------------------------------------------------------------------- 1 | export default function (str, position) { 2 | return [str.charAt(position), str.charAt(position - 1)] 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/isNotWord.js: -------------------------------------------------------------------------------- 1 | export default function (isBlankCharacter, isDelimiter, chars) { 2 | // The word is (no charactor || blank || delimiter)(!delimiter). 3 | return ( 4 | (chars[0] !== '' && 5 | !isBlankCharacter(chars[1]) && 6 | !isDelimiter(chars[1])) || 7 | isDelimiter(chars[0]) 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/skipToDelimiter.js: -------------------------------------------------------------------------------- 1 | import skipCharacters from '../skipCharacters' 2 | import getNext from './getNext' 3 | 4 | export default function skipToDelimiter(str, position, isDelimiter) { 5 | return skipCharacters(getNext, 1, str, position, (chars) => { 6 | // Proceed the position between two characters as (!delimiter delimiter) || (delimiter !delimiter) || (!delimiter !delimiter). 7 | // Return false to stop an infinite loop when the character undefined. 8 | return chars[1] && !isDelimiter(chars[0]) && !isDelimiter(chars[1]) 9 | }) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/DelimiterDetectAdjuster/skipToWord.js: -------------------------------------------------------------------------------- 1 | import skipCharacters from '../skipCharacters' 2 | import getPrev from './getPrev' 3 | 4 | export default function (str, position, isWordEdge) { 5 | return skipCharacters(getPrev, 1, str, position, isWordEdge) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/TextSelectionAdjuster.js: -------------------------------------------------------------------------------- 1 | export default class TextSelectionAdjuster { 2 | backFromBegin(str, position, spanConfig) {} 3 | 4 | forwardFromEnd(str, position, spanConfig) {} 5 | 6 | forwardFromBegin(str, position, spanConfig) {} 7 | 8 | backFromEnd(str, position, spanConfig) {} 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/reduce2hash.js: -------------------------------------------------------------------------------- 1 | export default function (key = 'name') { 2 | return function (hash, element) { 3 | hash[element[key]] = element 4 | return hash 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/skipBlank.js: -------------------------------------------------------------------------------- 1 | import skipCharacters from './skipCharacters' 2 | 3 | const getNow = function (str, position) { 4 | return str.charAt(position) 5 | } 6 | const skipForwardBlank = function (str, position, isBlankCharacter) { 7 | return skipCharacters(getNow, 1, str, position, isBlankCharacter) 8 | } 9 | const skipBackBlank = function (str, position, isBlankCharacter) { 10 | return skipCharacters(getNow, -1, str, position, isBlankCharacter) 11 | } 12 | 13 | export default { 14 | forward: skipForwardBlank, 15 | back: skipBackBlank 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/MenuState/skipCharacters.js: -------------------------------------------------------------------------------- 1 | export default function (getChars, step, str, position, predicate) { 2 | while (predicate(getChars(str, position))) position += step 3 | 4 | return position 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/OriginalData/StatusBar/html.js: -------------------------------------------------------------------------------- 1 | const html = ` 2 | 5 | ` 6 | 7 | export default html 8 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/PersistenceInterface/isTxtFile.js: -------------------------------------------------------------------------------- 1 | import path from 'path-browserify' 2 | 3 | export default function (fileName) { 4 | return path.extname(fileName) === '.txt' 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/PersistenceInterface/readAnnotationFile/parseFileContent.js: -------------------------------------------------------------------------------- 1 | import SimpleInlineTextAnnotation from '@pubann/simple-inline-text-annotation' 2 | 3 | export default function parseFileContent(fileContent) { 4 | try { 5 | const annotation = SimpleInlineTextAnnotation.parse(fileContent) 6 | 7 | return annotation 8 | } catch { 9 | return null 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/PersistenceInterface/readFile.js: -------------------------------------------------------------------------------- 1 | export default async function (file) { 2 | return new Promise((resolve) => { 3 | const reader = new FileReader() 4 | 5 | reader.onload = (event) => resolve(event) 6 | reader.readAsText(file) 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/BlockEditMode/create.js: -------------------------------------------------------------------------------- 1 | export default function ( 2 | annotationModel, 3 | commander, 4 | textSelectionAdjuster, 5 | spanConfig 6 | ) { 7 | const { begin, end } = annotationModel.getTextSelection( 8 | spanConfig, 9 | textSelectionAdjuster 10 | ) 11 | 12 | if (annotationModel.validateNewBlockSpan(begin, end)) { 13 | const command = commander.factory.createBlockSpanCommand({ 14 | begin, 15 | end 16 | }) 17 | 18 | commander.invoke(command) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/EditMode/index.js: -------------------------------------------------------------------------------- 1 | export default class EditMode { 2 | // Interface methods 3 | createSpanWithTouchDevice() {} 4 | expandSpanWithTouchDevice() {} 5 | shrinkSpanWithTouchDevice() {} 6 | editTextWithTouchDevice() {} 7 | editProperties() {} 8 | relationClicked() {} 9 | relationBollardClicked(entity) { 10 | entity.focus() 11 | } 12 | applyTextSelectionWithTouchDevice() {} 13 | manipulateAttribute() {} 14 | showPallet() {} 15 | hidePallet() {} 16 | get isPalletShown() { 17 | return false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/ModeTransitionReactor/EditorCSS.js: -------------------------------------------------------------------------------- 1 | export default class EditorCSS { 2 | constructor(editorHTMLElement) { 3 | this._editorHTMLElement = editorHTMLElement 4 | } 5 | 6 | clear() { 7 | for (const cssClass of this._editorHTMLElement.classList) { 8 | if (cssClass.startsWith('textae-editor__mode')) { 9 | this._editorHTMLElement.classList.remove(cssClass) 10 | } 11 | } 12 | } 13 | 14 | setFor(mode) { 15 | this._editorHTMLElement.classList.add(`textae-editor__mode--${mode}`) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/PalletFactory/bindPalletEvents/checkButtonEnable.js: -------------------------------------------------------------------------------- 1 | export default function (targetNode) { 2 | return !targetNode.classList.contains( 3 | 'textae-editor__pallet__table-button--disabled' 4 | ) 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/SelectionWrapper/isNodeBlockSpan.js: -------------------------------------------------------------------------------- 1 | export default function (node) { 2 | return node.classList.contains('textae-editor__block') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/SelectionWrapper/isNodeDenotationSpan.js: -------------------------------------------------------------------------------- 1 | export default function (node) { 2 | return node.classList.contains('textae-editor__span') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/SelectionWrapper/isNodeStyleSpan.js: -------------------------------------------------------------------------------- 1 | export default function (node) { 2 | return node.classList.contains('textae-editor__style') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/SelectionWrapper/isNodeTextBox.js: -------------------------------------------------------------------------------- 1 | export default function (node) { 2 | return node.classList.contains('textae-editor__text-box') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/TermEditMode/SpanEditor/isInSelected.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/Editor/UseCase/Presenter/EditModeSwitch/TermEditMode/SpanEditor/isInSelected.js -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/TermEditMode/SpanEditor/isPositionBetweenSpan.js: -------------------------------------------------------------------------------- 1 | export default function (span, position) { 2 | if (!span) { 3 | return false 4 | } 5 | 6 | return span.begin < position && position < span.end 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/clearTextSelection.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | window.getSelection().removeAllRanges() 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/isTextSelectionInTextBox.js: -------------------------------------------------------------------------------- 1 | export default function isTextSelectionInTextBox(textBoxHTMLElement) { 2 | const selection = window.getSelection() 3 | return ( 4 | selection.type === 'Range' && 5 | textBoxHTMLElement.contains(selection.anchorNode) && 6 | textBoxHTMLElement.contains(selection.focusNode) 7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/EditModeSwitch/selectSpan.js: -------------------------------------------------------------------------------- 1 | export default function (selectionModel, rangeOfSpans, event, spanID) { 2 | if (rangeOfSpans.length) { 3 | selectionModel.selectSpanRange(rangeOfSpans) 4 | return 5 | } 6 | 7 | if (event.ctrlKey || event.metaKey) { 8 | selectionModel.span.toggle(spanID) 9 | return 10 | } 11 | 12 | selectionModel.selectSpan(spanID) 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/Presenter/getIsDelimiterFunc.js: -------------------------------------------------------------------------------- 1 | export default function (menuState, spanConfig) { 2 | if (menuState.isPushed('boundary detection')) { 3 | return (char) => spanConfig.isDelimiter(char) 4 | } else { 5 | return () => true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/getEntityHTMLelementFromChild.js: -------------------------------------------------------------------------------- 1 | export default function (elementInEntityHtmlelement) { 2 | return elementInEntityHtmlelement.closest('.textae-editor__signboard') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/AnnotationsForPred/getValueType.js: -------------------------------------------------------------------------------- 1 | export default function (obj) { 2 | if (obj === true) { 3 | return 'flag' 4 | } else if (typeof obj === 'number') { 5 | return 'numeric' 6 | } else if (typeof obj === 'string') { 7 | return 'string' 8 | } else { 9 | throw `${JSON.stringify(obj)} is an unexpected value for an Attribute.` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/fillDefaultValueOfSelectionAttributes/getSelectionAttributes.js: -------------------------------------------------------------------------------- 1 | export default function (config) { 2 | return config.filter((a) => a['value type'] === 'selection') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/fillInferDefinitionFromAnnotation/fill.js: -------------------------------------------------------------------------------- 1 | // Complement the config with the generated Attribute definition. 2 | // Does not override the existing Attribute definition. 3 | export default function (config, newAttributeDefinitions) { 4 | for (const newDef of newAttributeDefinitions) { 5 | const index = config.findIndex((a) => a.pred === newDef.pred) 6 | if (index !== -1) { 7 | config[index] = { ...newDef, ...config[index] } 8 | } else { 9 | config.push(newDef) 10 | } 11 | } 12 | 13 | return config 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/fillInferDefinitionFromAnnotation/index.js: -------------------------------------------------------------------------------- 1 | import fill from './fill' 2 | import inferDefinitionFromAnnotation from './inferDefinitionFromAnnotation' 3 | 4 | export default function (config, annotations) { 5 | const inferDefinitions = inferDefinitionFromAnnotation(annotations) 6 | return fill(config, inferDefinitions) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/fillInferDefinitionFromAnnotation/inferDefinitionFromAnnotation/index.js: -------------------------------------------------------------------------------- 1 | import getAnnotationMap from '../../getAnnotationMap' 2 | 3 | // Generates a definition of an attribute by inferring a definition from the value of an annotation. 4 | export default function (annotations) { 5 | return [...getAnnotationMap(annotations).values()].map((a) => a.definition) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/fillMandatoryValueOfNumericAttributes.js: -------------------------------------------------------------------------------- 1 | import clone from '../clone' 2 | import { DEFAULT, STEP } from '../../../../NumericAttributeDefinition' 3 | 4 | export default function (config) { 5 | config = clone(config) 6 | 7 | for (const a of config.filter((a) => a['value type'] === 'numeric')) { 8 | if (!Object.prototype.hasOwnProperty.call(a, 'default')) { 9 | a.default = DEFAULT 10 | } 11 | if (!Object.prototype.hasOwnProperty.call(a, 'step')) { 12 | a.step = STEP 13 | } 14 | } 15 | 16 | return config 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/AttributeConfigurationGenerator/getAnnotationMap.js: -------------------------------------------------------------------------------- 1 | import AnnotationsForPred from './AnnotationsForPred' 2 | 3 | export default function (annotations) { 4 | return annotations.reduce((map, attr) => { 5 | if (map.has(attr.pred)) { 6 | map.get(attr.pred).push(attr.obj) 7 | } else { 8 | map.set(attr.pred, new AnnotationsForPred(attr)) 9 | } 10 | return map 11 | }, new Map()) 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/patchConfiguration/clone.js: -------------------------------------------------------------------------------- 1 | export default function (config) { 2 | return config ? JSON.parse(JSON.stringify(config)) : {} 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/setAnnotationAndConfiguration.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @param {import('./MenuState').MenuState} menuState 4 | * @param {import('../AnnotationModel').AnnotationModel} annotationModel 5 | */ 6 | export default function setAnnotationAndConfiguration( 7 | validConfig, 8 | menuState, 9 | spanConfig, 10 | annotationModel, 11 | annotation, 12 | functionAvailability 13 | ) { 14 | menuState.setPushButtons(validConfig) 15 | spanConfig.set(validConfig) 16 | annotationModel.reset(annotation, validConfig) 17 | functionAvailability.availability = validConfig['function availability'] 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/validateAttributeDefinitionAndAlert/index.js: -------------------------------------------------------------------------------- 1 | import alertifyjs from 'alertifyjs' 2 | import hasAllValueDefinitionOfSelectionAttributes from './hasAllValueDefinitionOfSelectionAttributes' 3 | 4 | export default function (annotation, config) { 5 | const error = hasAllValueDefinitionOfSelectionAttributes(annotation, config) 6 | 7 | if (error) { 8 | alertifyjs.error(error) 9 | return 10 | } 11 | 12 | return config 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/validateConfigurationAndAlert/validateConfiguration/toErrorMessage.js: -------------------------------------------------------------------------------- 1 | import anemone from '../../../../component/anemone' 2 | 3 | export default function (errors) { 4 | for (const e of errors) { 5 | if (e.keyword === 'required') { 6 | return `Invalid configuration: The attribute type whose predicate is '${e.data.pred}' misses a mandatory property, '${e.params.missingProperty}'.` 7 | } else if (e.instancePath.includes('color')) { 8 | return anemone`Invalid configuration: '${e.data}' is invalid color format.` 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/warningIfBeginEndOfSpanAreNotInteger/areNotBeginAndEndInteger.js: -------------------------------------------------------------------------------- 1 | export default function (annotation) { 2 | if (annotation.denotations) { 3 | for (const denotation of annotation.denotations) { 4 | if (denotation.span.begin !== parseInt(denotation.span.begin)) { 5 | return true 6 | } 7 | 8 | if (denotation.span.end !== parseInt(denotation.span.end)) { 9 | return true 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/UseCase/warningIfBeginEndOfSpanAreNotInteger/index.js: -------------------------------------------------------------------------------- 1 | import alertifyjs from 'alertifyjs' 2 | import areNotBeginAndEndInteger from './areNotBeginAndEndInteger' 3 | 4 | export default function (annotation) { 5 | if (areNotBeginAndEndInteger(annotation)) { 6 | alertifyjs.warning( 7 | `In the annotation file, some of the begin and end offsets of denotations were not integer values. 8 | TextAE converted them to integer values. 9 | However, to avoid a chance of unexpected rendering, please fix them.`, 10 | 15 11 | ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/Editor/control/ContextMenu/toContextMenuItem.js: -------------------------------------------------------------------------------- 1 | export default function ({ type, title, classList }) { 2 | return `

${title} 5 |

` 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/control/Menu/index.js: -------------------------------------------------------------------------------- 1 | import dohtml from 'dohtml' 2 | import bindEventHandler from './bindEventHandler' 3 | 4 | // The control is a control bar in an editor. 5 | export default class Menu { 6 | #el 7 | 8 | constructor(html, iconEventMap) { 9 | const el = dohtml.create(html) 10 | 11 | this.#el = el 12 | bindEventHandler(this.#el, iconEventMap) 13 | } 14 | 15 | get el() { 16 | return this.#el 17 | } 18 | 19 | // protected method 20 | _querySelector(selector) { 21 | return this.#el.querySelector(selector) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/lib/Editor/control/ToolBar/toButtonGroup/index.js: -------------------------------------------------------------------------------- 1 | import toButtonIcon from './toButtonIcon' 2 | 3 | export default function () { 4 | return (list) => ` 5 | 6 | ${list.map(toButtonIcon).join('\n')} 7 | ` 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/control/ToolBar/toButtonGroup/toButtonIcon.js: -------------------------------------------------------------------------------- 1 | export default function ({ type, title, classList }) { 2 | return ` 3 | 7 | 8 | ` 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/diffOfAnnotation/byID.js: -------------------------------------------------------------------------------- 1 | export default function byID(a, b) { 2 | if (a.id < b.id) { 3 | return -1 4 | } 5 | if (a.id > b.id) { 6 | return 1 7 | } 8 | return 0 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/diffOfAnnotation/index.js: -------------------------------------------------------------------------------- 1 | import { diff } from 'jsondiffpatch' 2 | import sortByID from './sortByID' 3 | 4 | export default function diffOfAnnotation(oldAnnotation, newAnnotation) { 5 | return diff(sortByID(oldAnnotation), sortByID(newAnnotation)) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/diffOfAnnotation/sortByID.js: -------------------------------------------------------------------------------- 1 | import byID from './byID' 2 | 3 | export default function sortByID({ 4 | text, 5 | denotations = [], 6 | attributes = [], 7 | relations = [], 8 | blocks = [] 9 | }) { 10 | return { 11 | text, 12 | denotations: denotations.sort(byID), 13 | attributes: attributes.sort(byID), 14 | relations: relations.sort(byID), 15 | blocks: blocks.sort(byID) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/Editor/editorCSSClassObserve.js: -------------------------------------------------------------------------------- 1 | export default function (eventEmitter, editorCSSClass) { 2 | eventEmitter 3 | .on('textae-event.resource.startLoad', () => editorCSSClass.startWait()) 4 | .on('textae-event.resource.endLoad', () => editorCSSClass.endWait()) 5 | .on('textae-event.resource.startSave', () => editorCSSClass.startWait()) 6 | .on('textae-event.resource.endSave', () => editorCSSClass.endWait()) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/forwardMethods.js: -------------------------------------------------------------------------------- 1 | export default function (delegator, getTargetFunction, methods) { 2 | for (const method of methods) { 3 | delegator[method] = (...args) => { 4 | const target = getTargetFunction() 5 | console.assert(target[method], `No ${method} method to forward`, target) 6 | 7 | return target[method].apply(target, args) 8 | } 9 | } 10 | 11 | return delegator 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/Editor/getLabelBackgroundColor.js: -------------------------------------------------------------------------------- 1 | import hexToRGBA from './hexToRGBA' 2 | 3 | export default function () { 4 | return hexToRGBA('#FFFFFF', 0.6) 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/Editor/getMatchPrefix.js: -------------------------------------------------------------------------------- 1 | export default function (namespace, type) { 2 | const namespaces = namespace.all 3 | const matchs = namespaces 4 | .filter((namespace) => namespace.prefix !== '_base') 5 | .filter((namespace) => { 6 | return type.indexOf(`${namespace.prefix}:`) === 0 7 | }) 8 | if (matchs.length === 1) return matchs[0] 9 | return null 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/Editor/getPalletButtonTitleFor.js: -------------------------------------------------------------------------------- 1 | import { MODE } from '../MODE' 2 | 3 | export default function getPalletButtonTitleFor(mode) { 4 | switch (mode) { 5 | case MODE.EDIT_DENOTATION: 6 | return 'Term Configuration' 7 | case MODE.EDIT_BLOCK: 8 | return 'Block Configuration' 9 | case MODE.EDIT_RELATION: 10 | return 'Relation Configuration' 11 | default: 12 | return '' 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/Editor/getRightElement.js: -------------------------------------------------------------------------------- 1 | export default function (editorHTMLElement, element, className) { 2 | console.assert(element, 'element MUST exists.') 3 | 4 | const all = editorHTMLElement.querySelectorAll(`.${className}`) 5 | const index = Array.from(all).indexOf(element) 6 | 7 | if (all.length - index > 1) { 8 | return all[index + 1] 9 | } 10 | 11 | return null 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/Editor/getRightSpanElement.js: -------------------------------------------------------------------------------- 1 | import getRightElement from './getRightElement' 2 | 3 | export default function (editorHTMLElement, spanId) { 4 | return getRightElement( 5 | editorHTMLElement, 6 | document.querySelector(`#${spanId}`), 7 | 'textae-editor__span' 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/getUrlMatches.js: -------------------------------------------------------------------------------- 1 | export default function (type) { 2 | // The regular-expression to parse URL. 3 | // See detail: 4 | // http://someweblog.com/url-regular-expression-javascript-link-shortener/ 5 | const urlRegex = 6 | /\(?(?:(http|https|ftp):\/\/)?(?:((?:[^\W\s]|\.|-|[:]{1})+)@{1})?((?:www.)?(?:[^\W\s]|\.|-)+[.][^\W\s]{2,4}|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::(\d*))?([/]?[^\s?]*[/]{1})*(?:\/?([^\s\n?[\]{}#]*(?:(?=\.)){1}|[^\s\n?[\]{}.#]*)?([.]{1}[^\s?#]*)?)?(?:\?{1}([^\s\n#[\]]*))?([#][^\s\n]*)?\)?/gi 7 | return urlRegex.exec(type) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/hexToRGBA.js: -------------------------------------------------------------------------------- 1 | export default function (hex, alpha) { 2 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) 3 | console.assert(result, `${hex} is not a hexadecimal color values!`) 4 | 5 | return `rgba(${parseInt(result[1], 16)}, ${parseInt( 6 | result[2], 7 | 16 8 | )}, ${parseInt(result[3], 16)}, ${alpha})` 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/Editor/isAndroid.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | // For development environments, Use the navigator.userAgent. 3 | // Because the navigator.userAgentData only work in the secure context(HTTPS). 4 | // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/userAgentData 5 | return /Android/.test(navigator.userAgent) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/Editor/isBoundaryCrossing.js: -------------------------------------------------------------------------------- 1 | export default function (begin, end, existSpan) { 2 | const isStartOfCandidateSpanBetweenExistsSpan = 3 | existSpan.begin < begin && begin < existSpan.end && existSpan.end < end 4 | 5 | const isEndOfCandidateSpanBetweenExistSpan = 6 | begin < existSpan.begin && existSpan.begin < end && end < existSpan.end 7 | 8 | return ( 9 | isStartOfCandidateSpanBetweenExistsSpan || 10 | isEndOfCandidateSpanBetweenExistSpan 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/Editor/isTouchable.js: -------------------------------------------------------------------------------- 1 | // https://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript/4819886#4819886 2 | export default function () { 3 | return ( 4 | 'ontouchstart' in window || 5 | navigator.maxTouchPoints > 0 || 6 | navigator.msMaxTouchPoints > 0 7 | ) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/Editor/loadAnnotation.js: -------------------------------------------------------------------------------- 1 | import DataSource from './DataSource' 2 | 3 | export default function loadAnnotation(eventEmitter, annotation) { 4 | if (!annotation.text) { 5 | return false 6 | } 7 | 8 | eventEmitter.emit( 9 | 'textae-event.resource.annotation.load.success', 10 | DataSource.createInstantSource(annotation) 11 | ) 12 | 13 | return true 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/Editor/observeElement.js: -------------------------------------------------------------------------------- 1 | import delegate from 'delegate' 2 | 3 | export default function (element) { 4 | // Prevent a selection text with shift keies. 5 | element.addEventListener('mousedown', (e) => { 6 | if (e.shiftKey) { 7 | e.preventDefault() 8 | } 9 | }) 10 | 11 | // Prevent a selection of an entity by the double-click. 12 | delegate(element, '.textae-editor__signboard', 'mousedown', (e) => 13 | e.preventDefault() 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/Editor/round.js: -------------------------------------------------------------------------------- 1 | // The value of getBoundingClientRect may contain 13 decimal places. 2 | // It's too fine to use as a style attribute, 3 | // so I'll round it to 2 decimal places, 4 | // which is below the rounding accuracy of Google Chrome and Firefox. 5 | export default function (val) { 6 | return Math.round(val * 100) / 100 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/Editor/toAnchorElement.js: -------------------------------------------------------------------------------- 1 | import anemone from '../component/anemone' 2 | 3 | export default function (displayName, href) { 4 | return () => 5 | href 6 | ? anemone`${displayName}` 7 | : anemone`${displayName}` 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/IntervalNotation/getLowwerCond.js: -------------------------------------------------------------------------------- 1 | import gte from './gte' 2 | import gt from './gt' 3 | 4 | export default function (str) { 5 | if (str.startsWith('[')) { 6 | return (right) => gte(new Number(str.replace('[', '')), right) 7 | } 8 | if (str.startsWith('(')) { 9 | return (right) => gt(new Number(str.replace('(', '')), right) 10 | } 11 | throw `${str} is not valid interval notation` 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/IntervalNotation/getUpperCond.js: -------------------------------------------------------------------------------- 1 | import gte from './gte' 2 | import gt from './gt' 3 | 4 | export default function (str) { 5 | if (str.endsWith(']')) { 6 | return (left) => gte(left, new Number(str.replace(']', ''))) 7 | } 8 | if (str.endsWith(')')) { 9 | return (left) => gt(left, new Number(str.replace(')', ''))) 10 | } 11 | throw `${str} is not valid interval notation` 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/IntervalNotation/gt.js: -------------------------------------------------------------------------------- 1 | export default function (left, right) { 2 | return left < right 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/IntervalNotation/gte.js: -------------------------------------------------------------------------------- 1 | export default function (left, right) { 2 | return left <= right 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/MODE.js: -------------------------------------------------------------------------------- 1 | export const MODE = { 2 | INIT: 'Init', 3 | VIEW: 'View', 4 | EDIT_DENOTATION: 'Term', 5 | EDIT_BLOCK: 'Block', 6 | EDIT_RELATION: 'Relation', 7 | EDIT_TEXT: 'Text' 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/component/CreateOrEditValueOfAttributeDefinitionDialog/inputDefault.js: -------------------------------------------------------------------------------- 1 | import anemone from '../anemone' 2 | 3 | export default function (showDefault, isDefault) { 4 | return () => 5 | showDefault 6 | ? anemone` 7 |
8 | 16 |
17 | ` 18 | : `` 19 | } 20 | -------------------------------------------------------------------------------- /src/lib/component/EditAttributeDefinitionDialog/isChanged.js: -------------------------------------------------------------------------------- 1 | export default function (orig, changed) { 2 | // Ignore non number value. 3 | return !Number.isNaN(parseFloat(changed)) && orig !== parseFloat(changed) 4 | } 5 | -------------------------------------------------------------------------------- /src/lib/component/EditAttributeDefinitionDialog/template.js: -------------------------------------------------------------------------------- 1 | import inputAttributeDefinition from '../inputAttributeDefinition' 2 | 3 | export default function (componentClassName, context) { 4 | return ` 5 |
6 | ${inputAttributeDefinition(componentClassName, context)} 7 |
` 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/component/HelpDialog.js: -------------------------------------------------------------------------------- 1 | import Dialog from './Dialog' 2 | 3 | export default class HelpDialog extends Dialog { 4 | constructor() { 5 | super( 6 | 'Help (Keyboard short-cuts)', 7 | `
8 | 22 | `, 23 | 24 | { 25 | maxWidth: 523 26 | } 27 | ) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/lib/component/Pallet/enableJqueryDraggable.js: -------------------------------------------------------------------------------- 1 | import $ from 'jquery' 2 | import 'jquery-ui/ui/widgets/draggable' 3 | 4 | export default function (element, editorHTMLElement) { 5 | $(element).draggable({ 6 | containment: editorHTMLElement 7 | }) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/component/Pallet/setHeightWithin.js: -------------------------------------------------------------------------------- 1 | const BORDER_HEIGHT = 7 * 2 2 | 3 | export default function (pallet, height) { 4 | if (height - BORDER_HEIGHT <= pallet.offsetHeight) { 5 | pallet.style.height = `${height - BORDER_HEIGHT}px` 6 | } else { 7 | pallet.style.height = null 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/component/Pallet/setWidthWithin.js: -------------------------------------------------------------------------------- 1 | export default function (pallet, width) { 2 | pallet.style.width = 'auto' 3 | 4 | if (width - 2 <= pallet.offsetWidth) { 5 | pallet.style.width = `${width - 4}px` 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/component/SaveAnnotationDialog/bind/createDownloadPathForFormat.js: -------------------------------------------------------------------------------- 1 | import createDownloadPath from '../../createDownloadPath' 2 | import SimpleInlineTextAnnotation from '@pubann/simple-inline-text-annotation' 3 | 4 | export default function createDownloadPathForFormat(data, format) { 5 | if (format === 'json') { 6 | return createDownloadPath(data) 7 | } else if (format === 'inline') { 8 | const inlineData = SimpleInlineTextAnnotation.generate(data) 9 | 10 | const blob = new Blob([inlineData], { type: 'text/plain;charset=utf-8' }) 11 | return URL.createObjectURL(blob) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/component/SaveAnnotationDialog/bind/downloadAnnotationFile/downloadAnnotation.js: -------------------------------------------------------------------------------- 1 | // Using an existing tag to following process, it cause the click event to fire twice, resulting an error. 2 | // Creating and using a temporary link (tempLink) prevents the re-triggering event. 3 | 4 | export default function downloadAnnotation(downloadPath, fileName) { 5 | const tempLink = document.createElement('a') 6 | tempLink.setAttribute('href', downloadPath) 7 | tempLink.setAttribute('download', fileName) 8 | document.body.appendChild(tempLink) 9 | tempLink.click() 10 | document.body.removeChild(tempLink) 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/component/SaveAnnotationDialog/bind/downloadAnnotationFile/index.js: -------------------------------------------------------------------------------- 1 | import createDownloadPathForFormat from '../createDownloadPathForFormat' 2 | import downloadAnnotation from './downloadAnnotation' 3 | 4 | export default function downloadAnnotationFile(e, data, format, eventEmitter) { 5 | e.preventDefault() 6 | 7 | const downloadPath = createDownloadPathForFormat(data, format) 8 | downloadAnnotation(downloadPath, e.target.previousElementSibling.value) 9 | 10 | eventEmitter.emit('textae-event.resource.annotation.save', data) 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/component/SaveAnnotationDialog/bind/viewSource.js: -------------------------------------------------------------------------------- 1 | import createDownloadPathForFormat from './createDownloadPathForFormat' 2 | 3 | export default function viewSource(data, format, eventEmitter) { 4 | const downloadPath = createDownloadPathForFormat(data, format) 5 | window.open(downloadPath, '_blank') 6 | 7 | eventEmitter.emit('textae-event.resource.annotation.save', data) 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/component/SaveConfigurationDialog/jsonDiff.js: -------------------------------------------------------------------------------- 1 | import { create } from 'jsondiffpatch' 2 | import { format } from 'jsondiffpatch/formatters/html' 3 | 4 | const jsond = create({ 5 | objectHash(obj, index) { 6 | return obj.id || `$$index:${index}` 7 | } 8 | }) 9 | 10 | export default function (originalConfig, editedConfig) { 11 | const delta = jsond.diff(originalConfig, editedConfig) 12 | return format(delta, originalConfig) 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/EscapeSequence.js: -------------------------------------------------------------------------------- 1 | export default class EscapeSequence { 2 | static escape(str) { 3 | return str.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r') 4 | } 5 | 6 | static decode(str) { 7 | return str.replace(/\\n/g, '\n').replace(/\\t/g, '\t').replace(/\\r/g, '\r') 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/bindAddCharacter/addCharacterRow/validateCharacter.js: -------------------------------------------------------------------------------- 1 | import alertifyjs from 'alertifyjs' 2 | import EscapeSequence from '../../EscapeSequence' 3 | 4 | export default function validateCharacter(char, currentCharacters) { 5 | if (currentCharacters.includes(char)) { 6 | alertifyjs.warning(`${char} is already added.`) 7 | return false 8 | } 9 | 10 | if (EscapeSequence.decode(char).length > 1) { 11 | alertifyjs.warning('Only one character is allowed.') 12 | return false 13 | } 14 | 15 | return true 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/bindAddCharacter/index.js: -------------------------------------------------------------------------------- 1 | import delegate from 'delegate' 2 | import addCharacterRow from './addCharacterRow' 3 | 4 | export default function bindAddCharacter(content) { 5 | delegate( 6 | content, 7 | '.textae-editor__setting-dialog__delimiter-character-add-button', 8 | 'click', 9 | () => addCharacterRow(content, 'delimiter') 10 | ) 11 | 12 | delegate( 13 | content, 14 | '.textae-editor__setting-dialog__blank-character-add-button', 15 | 'click', 16 | () => addCharacterRow(content, 'blank') 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/reflectImmediately/bindChangeLineHeight.js: -------------------------------------------------------------------------------- 1 | import delgate from 'delegate' 2 | import debounce300 from './debounce300' 3 | import redrawAllEditor from './redrawAllEditor' 4 | 5 | export default function (content, textBox) { 6 | delgate( 7 | content, 8 | '.textae-editor__setting-dialog__line-height-text', 9 | 'change', 10 | debounce300((e) => { 11 | textBox.lineHeight = e.target.value 12 | redrawAllEditor() 13 | }) 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/reflectImmediately/bindChangeLockConfig.js: -------------------------------------------------------------------------------- 1 | import delgate from 'delegate' 2 | import debounce300 from './debounce300' 3 | 4 | export default function (content, typeDictionary) { 5 | delgate( 6 | content, 7 | '.textae-editor__setting-dialog__lock-config-text', 8 | 'change', 9 | debounce300((e) => { 10 | if (e.target.checked) { 11 | typeDictionary.lockEdit() 12 | } else { 13 | typeDictionary.unlockEdit() 14 | } 15 | }) 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/reflectImmediately/bindChangeTypeGap.js: -------------------------------------------------------------------------------- 1 | import delgate from 'delegate' 2 | import debounce300 from './debounce300' 3 | 4 | export default function (content, typeGap, textBox) { 5 | delgate( 6 | content, 7 | '.textae-editor__setting-dialog__type-gap-text', 8 | 'change', 9 | debounce300((e) => { 10 | typeGap.value = Number(e.target.value) 11 | content.querySelector( 12 | '.textae-editor__setting-dialog__line-height-text' 13 | ).value = textBox.lineHeight 14 | }) 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/reflectImmediately/debounce300.js: -------------------------------------------------------------------------------- 1 | import debounce from 'debounce' 2 | 3 | export default function (func) { 4 | return debounce(func, 300) 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/reflectImmediately/redrawAllEditor.js: -------------------------------------------------------------------------------- 1 | // Redraw all editors in tha windows. 2 | export default function redrawAllEditor() { 3 | const event = new Event('resize') 4 | window.dispatchEvent(event) 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/saveAutocompletionWs.js: -------------------------------------------------------------------------------- 1 | import validateConfiguration from './validateConfiguration' 2 | 3 | export default function bindChangeAutocompletionWs(content, typeDictionary) { 4 | const newValue = content.querySelector( 5 | '.textae-editor__setting-dialog__autocompletion_ws-text' 6 | ).value 7 | 8 | validateConfiguration({ 9 | autocompletion_ws: newValue 10 | }) 11 | 12 | typeDictionary.autocompletionWs = newValue 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/template/escapeForDisplay.js: -------------------------------------------------------------------------------- 1 | import escape from 'lodash.escape' 2 | import EscapeSequence from '../EscapeSequence' 3 | 4 | export default function escapeForDisplay(str) { 5 | // First, escape newline, tab, and carriage returns to display them. 6 | const replaced = EscapeSequence.escape(str) 7 | 8 | // Then, escape special HTML characters to ensure safe rendering in HTML. 9 | return escape(replaced) 10 | } 11 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/template/toBlankCharacterRowElement.js: -------------------------------------------------------------------------------- 1 | import escapeForDisplay from './escapeForDisplay' 2 | 3 | export default function toBlankCharacterRowElement(char) { 4 | return ` 5 | 6 | 7 | ${escapeForDisplay(char)} 8 | 9 | 10 | ` 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/template/toDelimiterCharacterRowElement.js: -------------------------------------------------------------------------------- 1 | import escapeForDisplay from './escapeForDisplay' 2 | 3 | export default function toDelimiterCharacterRowElement(char) { 4 | return ` 5 | 6 | 7 | ${escapeForDisplay(char)} 8 | 9 | 10 | ` 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/template/toFunctionAvailabilityLabelElement.js: -------------------------------------------------------------------------------- 1 | export default function toFunctionAvailabilityLabelElement( 2 | functionAvailability, 3 | name 4 | ) { 5 | return ` 6 | ` 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/component/SettingDialog/validateConfiguration.js: -------------------------------------------------------------------------------- 1 | import Ajv from 'ajv' 2 | import addFormats from 'ajv-formats' 3 | import configurationScheme from '../../configurationScheme.json' 4 | 5 | const ajv = new Ajv({ verbose: true }) 6 | addFormats(ajv, ['uri-reference', 'regex']) 7 | const validate = ajv.compile(configurationScheme) 8 | 9 | export default function validateConfiguration(config) { 10 | if (!validate(config)) { 11 | console.warn(validate.errors) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/bindAttributeEvent/enableAttributeTabDrag/hideDropTargets.js: -------------------------------------------------------------------------------- 1 | export default function (e) { 2 | e.target 3 | .closest('.textae-editor__pallet__content') 4 | .classList.remove('textae-editor__pallet__content--dragging') 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/bindAttributeEvent/enableAttributeTabDrag/index.js: -------------------------------------------------------------------------------- 1 | import delegate from 'delegate' 2 | import showDropTargets from './showDropTargets' 3 | import hideDropTargets from './hideDropTargets' 4 | 5 | export default function (el) { 6 | delegate(el, '.textae-editor__pallet__attribute', 'dragstart', (e) => { 7 | e.dataTransfer.setData( 8 | 'application/x-textae-attribute-tab-old-index', 9 | e.target.dataset.index 10 | ) 11 | showDropTargets(e) 12 | }) 13 | 14 | delegate(el, '.textae-editor__pallet__attribute', 'dragend', (e) => { 15 | hideDropTargets(e) 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/bindAttributeEvent/enableAttributeTabDrag/showDropTargets.js: -------------------------------------------------------------------------------- 1 | export default function (e) { 2 | e.target 3 | .closest('.textae-editor__pallet__content') 4 | .classList.add('textae-editor__pallet__content--dragging') 5 | } 6 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/createContentHtml/flagAttributeTemplate.js: -------------------------------------------------------------------------------- 1 | import headerTemplate from './headerTemplate' 2 | import predicateControllerTemplate from './predicateControllerTemplate' 3 | import anemone from '../../anemone' 4 | 5 | export default function (context) { 6 | const { label, color } = context.attrDef 7 | 8 | return anemone` 9 | ${headerTemplate(context)} 10 |
11 |
12 | ${predicateControllerTemplate(context)} 13 | label: "${label || ''}" 14 | color: "${color || ''}" 15 |
16 |
17 | ` 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/createContentHtml/headerTemplate/getSelectedEntityLabel.js: -------------------------------------------------------------------------------- 1 | export default function (numberOfSelectedItems) { 2 | return numberOfSelectedItems === 1 3 | ? '1 item selected' 4 | : numberOfSelectedItems > 1 5 | ? `${numberOfSelectedItems} items selected` 6 | : '' 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/createContentHtml/showAddAttributeValueButton.js: -------------------------------------------------------------------------------- 1 | export default function (isLock) { 2 | return isLock 3 | ? '' 4 | : () => ` 5 | 6 | 7 | ` 8 | } 9 | -------------------------------------------------------------------------------- /src/lib/component/TypeValuesPallet/enableDrag.js: -------------------------------------------------------------------------------- 1 | export default function (el) { 2 | for (const attributeTab of el.querySelectorAll( 3 | '.textae-editor__pallet__attribute' 4 | )) { 5 | attributeTab.addEventListener('mousedown', (e) => { 6 | // Stop event propagation to prevent the jQueryUI.dragging widget 7 | // from disabling the default handling of mousedown events. 8 | e.stopPropagation() 9 | }) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/component/createDownloadPath.js: -------------------------------------------------------------------------------- 1 | export default function (dataObject) { 2 | const blob = new Blob([JSON.stringify(dataObject)], { 3 | type: 'application/json' 4 | }) 5 | 6 | return URL.createObjectURL(blob) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/component/enableHTMLElement.js: -------------------------------------------------------------------------------- 1 | // Since the style is specified by [disabled = "disabled"], 2 | // set the attribute to disabled without using the disable property. 3 | export default function (element, enable) { 4 | if (enable) { 5 | element.removeAttribute('disabled') 6 | } else { 7 | element.setAttribute('disabled', 'disabled') 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/lib/component/fetchAutocompleteCandidates.js: -------------------------------------------------------------------------------- 1 | export default function fetchAutocompleteCandidates(autocompletionWs, term) { 2 | const url = new URL(autocompletionWs, location) 3 | url.searchParams.append('term', term) 4 | 5 | return fetch(url.href).then((response) => { 6 | if (response.ok) { 7 | return response.json() 8 | } 9 | return [] 10 | }) 11 | } 12 | -------------------------------------------------------------------------------- /src/lib/component/getInputElementValue.js: -------------------------------------------------------------------------------- 1 | export default function (el, selector) { 2 | return ( 3 | el.querySelector(`input${selector}`) && 4 | el.querySelector(`input${selector}`).value 5 | ) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/component/getRandomColorString.js: -------------------------------------------------------------------------------- 1 | export default function () { 2 | return `#${getRandomHEXFrom64ToFF()}${getRandomHEXFrom64ToFF()}${getRandomHEXFrom64ToFF()}` 3 | } 4 | 5 | function getRandomHEXFrom64ToFF() { 6 | return Math.floor(Math.random() * 155 + 100).toString(16) 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/component/inputAttributeDefinition/inputAutocompletionWs.js: -------------------------------------------------------------------------------- 1 | import anemone from '../anemone' 2 | 3 | export default function inputAutocomletionWs( 4 | componentClassName, 5 | autocompletionWs 6 | ) { 7 | return () => anemone` 8 |
9 | 10 | 14 |
15 | ` 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/component/inputAttributeDefinition/inputDefault.js: -------------------------------------------------------------------------------- 1 | import anemone from '../anemone' 2 | 3 | export default function (componentClassName, defaultValue) { 4 | return () => anemone` 5 |
6 | 7 | 11 |
12 | ` 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/component/inputAttributeDefinition/inputMediaHeight.js: -------------------------------------------------------------------------------- 1 | import anemone from '../anemone' 2 | 3 | export default function (componentClassName, mediaHeight) { 4 | return () => anemone` 5 |
6 | 7 | 12 |
13 | ` 14 | } 15 | -------------------------------------------------------------------------------- /src/lib/component/isUserConfirm.js: -------------------------------------------------------------------------------- 1 | export default function isUserConfirm(hasChange) { 2 | const CONFIRM_DISCARD_CHANGE_MESSAGE = 3 | 'There is a change that has not been saved. If you proceed now, you will lose it.' 4 | 5 | return !hasChange || window.confirm(CONFIRM_DISCARD_CHANGE_MESSAGE) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/component/maximizeOverlay.js: -------------------------------------------------------------------------------- 1 | export default function (overlayDropzone) { 2 | const { element } = overlayDropzone 3 | element.classList.add( 4 | 'textae-editor__load-dialog__overlay-dropzone--maximized' 5 | ) 6 | element.style.zIndex = parseInt(element.style.zIndex) + 1 7 | } 8 | -------------------------------------------------------------------------------- /src/lib/component/revertMaximizeOverlay.js: -------------------------------------------------------------------------------- 1 | export default function (overlayDropzone, zIndexOfOverlayDropzone) { 2 | overlayDropzone.element.classList.remove( 3 | 'textae-editor__load-dialog__overlay-dropzone--maximized' 4 | ) 5 | overlayDropzone.element.style.zIndex = zIndexOfOverlayDropzone 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/css/images/btn_adjust_lineheight_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_adjust_lineheight_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_auto_adjust_lineheight_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_auto_adjust_lineheight_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_auto_replicate_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_auto_replicate_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_block_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_block_edit_mode_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_boundary_detection_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_boundary_detection_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_copy_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_copy_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_create_span_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_create_span_by_touch_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_cut_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_cut_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_delete_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_delete_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_edit_properties_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_edit_properties_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_edit_text_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_edit_text_by_touch_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_expand_span_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_expand_span_by_touch_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_help_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_help_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_import_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_import_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_new_entity_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_new_entity_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_pallet_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_pallet_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_pallet_modified_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_pallet_modified_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_paste_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_paste_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_redo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_redo_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_relation_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_relation_edit_mode_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_replicate_span_annotation_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_replicate_span_annotation_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_setting_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_setting_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_shrink_span_by_touch_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_shrink_span_by_touch_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_simple_view_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_simple_view_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_term_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_term_edit_mode_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_text_edit_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_text_edit_mode_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_undo_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_undo_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_upload_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_upload_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_upload_automatically_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_upload_automatically_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_upload_modified_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_upload_modified_16.png -------------------------------------------------------------------------------- /src/lib/css/images/btn_view_mode_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/btn_view_mode_16.png -------------------------------------------------------------------------------- /src/lib/css/images/keyhelp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/keyhelp.png -------------------------------------------------------------------------------- /src/lib/css/images/keyhelp.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/keyhelp.psd -------------------------------------------------------------------------------- /src/lib/css/images/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/link.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /src/lib/css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/src/lib/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /src/lib/css/textae-const.less: -------------------------------------------------------------------------------- 1 | @baseColor: rgb(100, 100, 215); 2 | @selected: red; 3 | -------------------------------------------------------------------------------- /src/lib/css/textae-editor-fontawsome.less: -------------------------------------------------------------------------------- 1 | .fontAwesomeIcon(@content) { 2 | position: relative; 3 | display: inline-block; 4 | font-family: FontAwesome; 5 | content: @content; 6 | } 7 | 8 | .attributeIcons() { 9 | &--flag:before { 10 | .fontAwesomeIcon('\f024'); 11 | } 12 | &--selection:before { 13 | .fontAwesomeIcon('\f0ca'); 14 | } 15 | &--numeric:before { 16 | .fontAwesomeIcon('\f2c9'); 17 | } 18 | &--string:before { 19 | .fontAwesomeIcon('\f27a'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/lib/css/textae-text-edit-dialog.less: -------------------------------------------------------------------------------- 1 | .textae-editor__text-edit-dialog { 2 | width: calc(100% - 300px); 3 | min-width: 360px; 4 | padding: 10px; 5 | border: 1px solid black; 6 | border-radius: 5px; 7 | background-color: #f0f0f0; 8 | 9 | &__title-bar { 10 | display: flex; 11 | justify-content: space-between; 12 | align-items: flex-start; 13 | margin-bottom: 10px; 14 | } 15 | 16 | &__text-box { 17 | width: 100%; 18 | margin-bottom: 10px; 19 | min-height: 150px; 20 | } 21 | 22 | &__button-bar { 23 | display: flex; 24 | justify-content: flex-end; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/lib/exceptions/FormatConversionError.js: -------------------------------------------------------------------------------- 1 | export default class FormatConversionError extends Error { 2 | constructor(message) { 3 | super(message) 4 | this.name = 'FormatConversionError' 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/isAbleToParseFloat.js: -------------------------------------------------------------------------------- 1 | export default function (str) { 2 | return !Number.isNaN(parseFloat(str)) 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/isJSON.js: -------------------------------------------------------------------------------- 1 | export default function (arg) { 2 | if (typeof arg !== 'string') { 3 | return false 4 | } 5 | 6 | try { 7 | JSON.parse(arg) 8 | } catch (e) { 9 | return false 10 | } 11 | 12 | return true 13 | } 14 | -------------------------------------------------------------------------------- /src/lib/isURI.js: -------------------------------------------------------------------------------- 1 | export default function (type) { 2 | return type.trim().startsWith('http') 3 | } 4 | -------------------------------------------------------------------------------- /src/lib/textae/Tool/EditorContainer/isTextFields.js: -------------------------------------------------------------------------------- 1 | export default function (htmlElement) { 2 | return ( 3 | htmlElement instanceof HTMLInputElement || 4 | htmlElement instanceof HTMLTextAreaElement 5 | ) 6 | } 7 | -------------------------------------------------------------------------------- /src/lib/textae/Tool/getMousePoint.js: -------------------------------------------------------------------------------- 1 | // Observe and record mouse position to return it. 2 | const lastMousePoint = {} 3 | 4 | document.querySelector('html').addEventListener('mousemove', (e) => { 5 | lastMousePoint.clientY = e.clientY 6 | lastMousePoint.pageY = e.pageY 7 | lastMousePoint.clientX = e.clientX 8 | }) 9 | 10 | export default function () { 11 | return lastMousePoint 12 | } 13 | -------------------------------------------------------------------------------- /src/lib/textae/index.js: -------------------------------------------------------------------------------- 1 | import alertifyjs from 'alertifyjs' 2 | import Tool from './Tool' 3 | import toEditor from './toEditor' 4 | import API from './API' 5 | 6 | export const tool = new Tool() 7 | 8 | export default function initializeTextAEEditor() { 9 | // Set position of toast messages. 10 | alertifyjs.set('notifier', 'position', 'top-right') 11 | 12 | return Array.from(document.querySelectorAll('.textae-editor')) 13 | .filter((element) => !element.dataset.textaeInitialized) 14 | .map((element) => toEditor(tool, element)) 15 | .map((editor) => new API(editor)) 16 | } 17 | -------------------------------------------------------------------------------- /src/lib/textae/toEditor.js: -------------------------------------------------------------------------------- 1 | import createEditor from '../createEditor' 2 | 3 | export default function toEditor(tool, element) { 4 | // Create an editor 5 | const editor = createEditor(element, tool) 6 | // Register an editor 7 | tool.registerEditor(element, editor) 8 | 9 | // Mark as initiated. 10 | element.dataset.textaeInitialized = true 11 | 12 | return editor 13 | } 14 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pubannotation/textae/4e173e6a73f53bbed48a0694bcab5c44562b72bb/tmp/.keep -------------------------------------------------------------------------------- /userAcceptanceTest/20210716_02.md: -------------------------------------------------------------------------------- 1 | ## Lock Edit Config 有効時のパレットの表示項目 2 | 3 | ### 背景 4 | 5 | 1. 6.4.52 で `Lock Edit Config`有効時に、Attribute タブの、定義削除ボタン、定義編集ボタンを無効にしました。 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. Term モードにする 11 | 3. 設定ダイアログをひらく`Lock Edit Config`にチェックを入れる 12 | 4. パレットを開く 13 | 5. 全選択ボタンが表示されないこと 14 | 6. 編集ボタンが表示されないこと 15 | 7. 削除ボタンが表示されないこと 16 | 8. Attirbute 追加タブが表示されないこと 17 | 9. `denote` タブを選ぶ 18 | 10. `Delete this predicate.`ボタンが無効であること 19 | 11. `Edit this predicate.`ボタンが無効であること 20 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210720_01.md: -------------------------------------------------------------------------------- 1 | ## パレットはマウスカーソルの近くに開く 2 | 3 | 1. Term モードにする 4 | 2. `Show label list editor [Q]`ボタンをクリックする 5 | 3. パレットがボタンの近くに開くこと 6 | 4. `Q`キーを押す 7 | 5. パレットがマウスカーソルの近くに開くこと 8 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210720_02_mouse.md: -------------------------------------------------------------------------------- 1 | ## パレットはドラッグできる 2 | 3 | 1. Term モードにする 4 | 2. Entity を選択する 5 | 3. `Q`キーを押す 6 | 4. パレットがドラッグアンドドロップで移動できること 7 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210720_04.md: -------------------------------------------------------------------------------- 1 | ## Entity 選択時の Entity の見た目の変化 2 | 3 | ### 背景 4 | 5 | 1. 6.2.28 で Entity のエンドポイントの表示をやめました。 6 | 2. 6.4.63 で、Block モード以外のモードでも、背景色を薄くつける対応をしました 7 | 3. このとき BlockEntity を選択肢ときにボーダーが赤色にならなくなりました 8 | 4. 6.4.72 で、対応しました 9 | 10 | ### DenotationEntity 11 | 12 | 1. Term モードにする 13 | 2. Entity を選択する 14 | 3. Entity のラベルのボーダーが赤色になること 15 | 16 | ### BlockEntity 17 | 18 | 1. Editor1 を選択 19 | 2. Block モードにする 20 | 3. Entity を選択する 21 | 4. Entity のラベルのボーダーが赤色になること 22 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210805_01.md: -------------------------------------------------------------------------------- 1 | ## 保存ファイル名は、読み込んだコンフィグレーションのファイル名 2 | 3 | ### 背景 4 | 5 | 1. コンフィグレーション保存ダイアログの保存ファイルの初期値は、最後に読み込んだコンフィグレーションのファイル名です 6 | 2. 6.1.4 で対応しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. `Show label list editor [Q]`ボタンをクリックする 12 | 3. コンフィグレーション読込ダイアログを開く 13 | 4. ローカルファイルから`1_config.json`を読み込む 14 | 5. `Show label list editor [Q]`ボタンをクリックする 15 | 6. コンフィグレーション保存ダイアログを開く 16 | 7. Local 欄に`1_config.json`が表示されていること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210805_03.md: -------------------------------------------------------------------------------- 1 | ## 境界検知はデフォルトで有効 2 | 3 | ### 背景 4 | 5 | 1. 6.1.5 から、config の `boundarydetection` の値で境界検知の有効無効を指定できるようになりました 6 | 2. 7.15.0 で境界検知をデフォルトで有効にしました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. 境界検知が有効であること 11 | 2. `ゆりかごのうた.json`を読み込む 12 | 3. 境界検知が無効になること 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210805_04.md: -------------------------------------------------------------------------------- 1 | ## 行の高さ自動調整はデフォルトで有効 2 | 3 | ### 背景 4 | 5 | 1. 6.1.5 から、config の `autolineheight` の値で行の高さ自動調整の有効無効を指定できるようになりました 6 | 2. 7.15.0 で行の高さ自動調整をデフォルトで有効にしました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. 行の高さ自動調整が無効であること 12 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210805_05_keyboard.md: -------------------------------------------------------------------------------- 1 | ## シュートカットキーでパレットを開いたときに画面からはみ出ないこと 2 | 3 | ### 背景 4 | 5 | 1. 6.4.78 でパレットをエディターの右端からはみ出ないようにしました 6 | 2. 横スクロールバーが表示されているときに、パレットが下からはみ出ます 7 | 3. windew.innerHeight を使うとスクロールバーを考慮しない高さがとれます 8 | 4. document.documentElement.clientHeight を使えばスクロールバーを考慮した高さがとれます 9 | 5. 6.4.122 で対応しました 10 | 11 | ### -- 手段 -- 12 | 13 | 1. Term モードにする 14 | 2. ブラウザの横スクロールバーが表示されるまで、ブラウザの幅を縮める 15 | 3. エディターのブラウザの下端ギリギリ、右端ギリギリをクリックする 16 | 4. `Q`キーを押す 17 | 5. パレットがブラウザからはみ出ないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210806_01.md: -------------------------------------------------------------------------------- 1 | ## Ctrl/Cmd を押して複数選択、Term モードで 2 | 3 | 1. Term モードにする 4 | 2. Span と Span を同時に複数選択する 5 | 3. Entity と Entity を同時に複数選択する 6 | 4. Span と Entity を同時に複数選択する 7 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210806_02.md: -------------------------------------------------------------------------------- 1 | ## Ctrl/Cmd を押しながら、新しく作った Relation をラベルを使って複数選択 2 | 3 | 1. 新規に Relation を作る 4 | 2. 他の Relation を選択 5 | 3. Ctrl を押しながら新しく作った Relation のラベルをクリック 6 | 4. 両方の Relation が選択されること 7 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210812_02.md: -------------------------------------------------------------------------------- 1 | ## 自動レプリケーション機能 2 | 3 | ### Boundary Detection 有効時の動作 4 | 5 | 1. `Auto Replicate`ボタンを押下状態にする 6 | 2. 単語の一部を選択する 7 | 3. 単語単位でレプリカが作られること 8 | 9 | ### Boundary Detection 無効時の動作 10 | 11 | 1. `Auto Replicate`ボタンを押下状態にする 12 | 2. 単語の一部を選択する 13 | 3. 文字単位でレプリカが作られること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210817_02.md: -------------------------------------------------------------------------------- 1 | ## multi tracks 2 | 3 | ### Edit モード 4 | 5 | #### 背景 6 | 7 | 1. multi tracks でも json 上の annotation.text の位置は変わりません。 8 | 2. JSON validator の導入時に annotation.text を track 内から取ろうとするバグがありました。 9 | 3. 4.1.10 で alert からトーストに表示方法を変更しました 10 | 4. 5.0.0 で`Upload`ボタンの制御を有効無効から、星マークの有無に変更しました 11 | 12 | #### -- 手段 -- 13 | 14 | 1. multi_tracks.json が読み込めること 15 | 2. 読み込んだ時にトーストが表示されること 16 | 3. 文面は`track annotations have been merged to root annotations.` 17 | 4. Relation に track id が表示されること 18 | 5. `Upload`ボタンに星マークがつくこと 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210818_01.md: -------------------------------------------------------------------------------- 1 | ## Span の Entity をすべて削除したとき Span も一緒に削除する 2 | 3 | ### 背景 4 | 5 | 1. Entity のない Span を削除する機能があります 6 | 2. Entity を一つずつ消して行く場合は正常に動いていました 7 | 3. Entity を複数選択してまとめて消して Span の Entity がなくなったときに、Span が残るバグがありました 8 | 4. 4.1.8 で対応しました 9 | 5. 4.2.1 の開発中に、Span 削除時に unfocus するための DOM 要素が取得できずにエラーが起きました 10 | 11 | ### -- 手段 -- 12 | 13 | 1. Span に複数の Entity を作る 14 | 2. Span を選択解除する 15 | 3. すべての Entity を選択し、削除 16 | 4. Span が削除されること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210819_01.md: -------------------------------------------------------------------------------- 1 | ## Relation の Type を変更する 2 | 3 | ### 背景 4 | 5 | 1. 6.5.4 で namespace プロパティを\_namespace プロパティで参照してエラーが出るようになりました 6 | 2. 6.5.7 で対応しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Relation モードにする 12 | 3. Relation を選択する 13 | 4. `q`キーを押してパレットを開く 14 | 5. `locatedAt`を選択する 15 | 6. Relation のラベルが`locatedAt`に変わること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210825_01.md: -------------------------------------------------------------------------------- 1 | ## pubannotation 認証する際にポップアップブロックされる 2 | 3 | ### 背景 4 | 5 | 1. 6.1.14 から PubAnnotation の認証に対応しました 6 | 2. textae は PubAnnotation のログイン画面は新規ウインドウで開きます 7 | 3. ウインドウが閉じられた際に自動的に保存をしに行くために、ウインドウの状態を監視しています 8 | 4. ブラウザの設定よってはポップアップブロック機能によって新規ウインドウがひらけません 9 | 5. ウインドウが開けなかったときにエラーが起きていました 10 | 11 | ### 手段 12 | 13 | 1. ブラウザのポップアップブロック機能で http://localhost:8000/ を対象とする 14 | 2. アノテーション保存ダイアログを開く 15 | 3. URL に`/dev/server_auth`を入力して、Save ボタンを押す 16 | 4. ポップアップがブロックされること 17 | 5. 右上に`could not save`と赤色のトースト表示がされること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210827_02.md: -------------------------------------------------------------------------------- 1 | ## Editor の下の要素をクリックできる 2 | 3 | ### 背景 4 | 5 | 1. テキストの余白が上に大きく、下は少ないように見せています 6 | 2. 実際のテキストはパラグラフの中央にあります 7 | 3. Editor の下に透明のパラグラフがはみ出しています 8 | 4. はみ出たパラグラフの下の要素がクリックできません 9 | 5. 4.4.0 で Editor の`over-flow`スタイルに`hidden`属性を設定。はみ出たパラグラフを非表示にしました 10 | 6. 5.0.0 でコンテキストメニューを追加したときに、コンテキストメニューを Editor からはみ出させたくなりました 11 | 7. `over-flow`スタイルを設定する要素を、`.textae-editor`から、パラグラフのすぐ親の要素`.textae-editor__body__text-box`に変更しました 12 | 8. 6.0.0 でテキスト中の改行のレンダリングをパラグラフから、css の`white-space: pre-wrap;`に変更しました 13 | 14 | ### -- 手段 -- 15 | 16 | 1. Editor1 の下の input をクリックする 17 | 2. input にフォーカスがうつること 18 | 3. input に文字が入力できること 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210901_01.md: -------------------------------------------------------------------------------- 1 | ## annotation ファイル内の begin, end を整数に自動変換する 2 | 3 | ### 背景 4 | 5 | 1. annotation ファイル内の begin, end が文字列の場合、クロススパンの検出時にエラーが出ます 6 | 2. annotation ファイル内の begin, end が小数点を含む場合、生成する span の DOM の ID に`.`が含まれ、DOM の ID として不正な形式になります 7 | 3. 5.3.1 から、begin, end の値を自動的に整数に変換します 8 | 9 | ### -- 手段 -- 10 | 11 | 1. invalid.json を読み込む 12 | 2. トーストが表示されること 13 | 3. annotation をソース表示する 14 | 4. `T3`の begin が、ダブルクォートされた文字列ではなく、数値であること 15 | 5. `T3`の end が、少数ではなく、整数であること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210902_03.md: -------------------------------------------------------------------------------- 1 | ## Relation モードの背景色 2 | 3 | 1. Relation モードにする 4 | 2. 背景が薄ピンク色になること 5 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210902_05.md: -------------------------------------------------------------------------------- 1 | ## Relation の作成 2 | 3 | ### ctrl 4 | 5 | 1. Relation モードにする 6 | 2. ctrl(Mac の場合は Cmd)を押しながら Relation を作る 7 | 3. 選んでいた Entity と作った Relation が選択される 8 | 9 | ### shift 10 | 11 | 1. Relation モードにする 12 | 2. shift を押しながら Relation を作る 13 | 3. あとに選んだ Entity と作った Relation が選択される 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210907_02.md: -------------------------------------------------------------------------------- 1 | ## editor を選択して、editor 外をクリックすると、editor が選択解除される 2 | 3 | 1. フォーカスされない要素を click しても、Editor を選択解除していませんでした 4 | 2. 4.4.2 から Editor 外を click 時に、Editor を選択解除します 5 | 6 | ### -- 手段 -- 7 | 8 | 1. Editor をクリックする 9 | 2. Editor が選択されていること(背景色がベージュ) 10 | 3. 一番上の input の横の`Wellcome!`をクリックする 11 | 4. Editor が選択解除されること(背景色が白) 12 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210914_01.md: -------------------------------------------------------------------------------- 1 | ## リサイズ後も Relation のラベルクリックで Relation を選択できる 2 | 3 | ### 背景 4 | 5 | 1. jsPlumb は、Relation を描画した直後はラベルのクリックイベントを Relation のクリックイベントとして通知します 6 | 2. リサイズなどで Relation を書き直したとき、Relation を描画する SVG 要素を作り直したときに、ラベルのクリックイベントを通知しなくなります。 7 | 3. 6.1.43 で、描画直後の状態だけで、jsPlumb が常にラベルのクリックイベントを通知すると判断して、ラベルへのイベントハンドラー設定をなくしました 8 | 4. 6.2.38 で、再度ラベルにもイベントハンドラーを設定しました 9 | 5. 6.6.0 で、jsPlumb を廃止し SVG を直接描画することにしました 10 | 11 | ### -- 手段 -- 12 | 13 | 1. Relation モードにする 14 | 2. ブラウザをリサイズして、Relation を移動する 15 | 3. Relation のラベルをクリックする 16 | 4. Relation が選択されること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210914_02.md: -------------------------------------------------------------------------------- 1 | ## 親子 Span の親子とも左端が画面の左端にある親 Span を選択して、左から縮めたときに、親 Span が縮まること 2 | 3 | ### 背景 4 | 5 | 1. anchorNode が子 Span で、focusNode が親 Span のときは必ず anchorNode の Span(子 Span)を広げる処理をしていました 6 | 2. 5.3.2 で、focusNode(親 Span)が選択されているときは、親 Span を縮める処理にする判定を追加しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. `T1.a.b`の Span を選択せずに、左から、子 Span を超えて、縮める 13 | 4. `E1:a:b`の Span が縮まること 14 | 5. `T1.a.b`の Span を選択して、左から、子 Span を超えて、縮める 15 | 6. `T1.a.b`の Span が縮まること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210921_02.md: -------------------------------------------------------------------------------- 1 | ## Block モードで DenotationSpan をクリックしたら選択解除する 2 | 3 | ### 背景 4 | 5 | 1. 6.2.42 で対応しました 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Block モードにする 10 | 2. BlockSpan を選択 11 | 3. DenotationSpan をクリック 12 | 4. BlockSpan が選択解除されること 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210922_01.md: -------------------------------------------------------------------------------- 1 | ## Block モードで StyleSpan をクリックしたら選択解除する 2 | 3 | ### 背景 4 | 5 | 1. 6.2.41 で対応しました 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Block モードにする 10 | 2. BlockSpan を選択 11 | 3. StyleSpan をクリック 12 | 4. BlockSpan が選択解除されること 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210922_02.md: -------------------------------------------------------------------------------- 1 | ## スクロールしたときにコントロールバーが Editor の表示領域上部に張り付く 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 のコンテキストメニュー追加時に、コントロールバーのみ sticky して、コンテキストメニューは sticky しないことにしました。 6 | 2. 6.6.1 で sticky の実装を JavaScript から CSS に変更しました 7 | 3. Safari で sticky が動きませんでした 8 | 4. 6.6.3 で対応しました 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Editor を選択する 13 | 2. ブラウザをスクロールする 14 | 3. Editor がスクロールしても、コントロールバーがスクロールアウトせず、Editor の最上部にいつづけること 15 | 4. ブラウザをもっとスクロールする 16 | 5. Editor がスクロールアウトするときに、コントロールバーも一緒にスクロールアウトすること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210922_03.md: -------------------------------------------------------------------------------- 1 | ## Block モードで StyleSpan でマウスダウンして、BlockSpan を作る 2 | 3 | ### 背景 4 | 5 | 1. 6.2.48 で対応 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. Block モードにする 11 | 3. StyleSpan でマウスダウン、テキストでマウスアップ 12 | 4. BlockSpan ができること 13 | 5. StyleSpan でマウスダウン、DenotationSpan でマウスアップ 14 | 6. BlockSpan ができること 15 | 7. StyleSpan でマウスダウン、StyleSpan でマウスアップ 16 | 8. BlockSpan ができること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210929_01.md: -------------------------------------------------------------------------------- 1 | ## Block モードでテキストでマウスダウンして、BlockSpan を作る 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 で、テキストでのマウスアップに対応 6 | 2. 6.2.43 で、StyleSpan でのマウスアップに対応 7 | 3. 6.2.44 で、DenotationSpan でのマウスアップに対応 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. Block モードにする 13 | 3. テキストでマウスダウン、テキストでマウスアップ 14 | 4. BlockSpan ができること 15 | 5. テキストでマウスダウン、DenotationSpan でマウスアップ 16 | 6. BlockSpan ができること 17 | 7. テキストでマウスダウン、StyleSpan でマウスアップ 18 | 8. BlockSpan ができること 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210929_02.md: -------------------------------------------------------------------------------- 1 | ## Block モードで DenotationSpan でマウスダウンして、BlockSpan を作る 2 | 3 | ### 背景 4 | 5 | 1. 6.2.45 で、テキストでのマウスアップに対応 6 | 2. 6.2.46 で、DenotationSpan でのマウスアップに対応 7 | 3. 6.2.47 で、StyleSpan でのマウスアップに対応 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. Block モードにする 13 | 3. DenotationSpan でマウスダウン、テキストでマウスアップ 14 | 4. BlockSpan ができること 15 | 5. DenotationSpan でマウスダウン、DenotationSpan でマウスアップ 16 | 6. BlockSpan ができること 17 | 7. DenotationSpan でマウスダウン、StyleSpan でマウスアップ 18 | 8. BlockSpan ができること 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210929_03.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity の TypeGap 部分をクリックしたらエディタを選択する 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. Term モードにするでは対応していましたが、Block モードでは対応していませんでした。 7 | 3. 6.2.53 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Block モードにする 12 | 2. Editor の選択を解除する(背景色が白くなること) 13 | 3. BlockEntity の TypeGap 部分(ラベルの上の空間)をクリックする 14 | 4. Editor が選択され、背景色が紫色になること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210929_04.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity を選択する 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. BlockEntity を Term モードで選択できていましたが、Block モードでは選択できませんでした。 7 | 3. 6.2.54 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Term モードにする 12 | 2. BlockEntity のラベルをクリックする 13 | 3. BlockEntity が選択されないこと 14 | 4. Block モードにする 15 | 5. BlockEntity のラベルをクリックする 16 | 6. BlockEntity が選択されること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210930_01.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan を選択したときに自動的に BlockEntity を選択 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. BlockSpan は BlockEntity をただひとつ持つので、別々に選択する必要がありません 7 | 3. 6.2.59 で導入 8 | 9 | ### −− 手段 -- 10 | 11 | 1. Block モードにする 12 | 2. BlockSpan を選択する 13 | 3. BlockEntity が選択されること 14 | 4. BlockEntity を選択する 15 | 5. BlockSpan が選択されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210930_03.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーションに変更があるときは保存ボタンに星マークを表示 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの保存機能を追加しました 6 | 7 | ### -- 手段 -- 8 | 9 | 1. editor0 を選択 10 | 2. Setting ダイアログで`Lock Edit Config`のチェックを外す 11 | 3. `Show label list editor [Q]`ボタンをクリックする 12 | 4. コンフィグレーション保存ボタンに星マークがついていること 13 | 5. Local に保存する 14 | 6. コンフィグレーション保存ボタンに星マークが消えること 15 | 7. Type 定義を変更する 16 | 8. コンフィグレーション保存ボタンに星マークがついていること 17 | 9. UNDO する 18 | 10. コンフィグレーション保存ボタンに星マークが消えること 19 | 11. REDO する 20 | 12. コンフィグレーション保存ボタンに星マークがついていること 21 | 13. Local に保存する 22 | 14. コンフィグレーション保存ボタンに星マークが消えること 23 | -------------------------------------------------------------------------------- /userAcceptanceTest/20210930_04.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーションを UNDO/REDO したときにトーストを表示 2 | 3 | ### 背景 4 | 5 | 1. 5.2.0 からコンフィグレーションの UNDO/REDO 実行時にトーストを表示します 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Type 定義を変更する 10 | 2. UNDO する 11 | 3. 緑色のトーストが表示されること 12 | 4. REDO する 13 | 5. 緑色のトーストが表示されること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211028_01.md: -------------------------------------------------------------------------------- 1 | ## 実用的な annotation を開く 2 | 3 | 1. 4 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211029_01.md: -------------------------------------------------------------------------------- 1 | ## トラックをまたがって ID が重複しているときにバリデーションエラーにしないこと 2 | 3 | ### 背景 4 | 5 | 1. クロススパンの検出はトラックをまたがって判定が必要です。 6 | 2. ID の重複検出はトラックをまたがって判定する必要がありません。 7 | 3. ID の重複検出の際に、クロススパンの検出と同じ対象を使っていました。 8 | 4. 7.26.3 で修正しました。 9 | 10 | ### -- 手段 -- 11 | 12 | 1. invalid_multi.json を読む 13 | 2. ID が`track1_T1`と`track2_T1`の Entity が両方表示されること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211102_01.md: -------------------------------------------------------------------------------- 1 | ## Relation モードで Ctrl/Cmd を押して複数選択 2 | 3 | ### 背景 4 | 5 | 1. 5.0.5 で Entity -> Relation の順で選択した際に、Ctrl/Cmd を押していなくても、両方選択されるバグが発生 6 | 2. 6.1.28 で対応 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Relation モードにする 11 | 2. Entity を選択する 12 | 3. Relation をクリックする 13 | 4. Entity の選択が解除され、Relation が選択されること 14 | 5. Entity をクリックする 15 | 6. Relation の選択が解除され、Entity が選択されること 16 | 7. Ctrl/Cmd を押して Relation をクリックする 17 | 8. Entity と Relation が両方選択されること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211109_02.md: -------------------------------------------------------------------------------- 1 | ## パレットを開きながらモードを変更したときに選択解除 2 | 3 | ### 背景 4 | 5 | 1. Body クリック時は選択解除するときにパレットが開いていると選択解除しません。 6 | 2. モード変更時も、パレットが開いていると選択解除していませんでした。 7 | 3. モード変更時は、パレットを閉じるのと、選択解除を両方実行するようにしました。 8 | 4. 6.1.61 で対応しました。 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Entity を選択する 13 | 2. パレットを開く 14 | 3. モードを変更する 15 | 4. Entity が選択解除されること 16 | 5. パレットが閉じること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211109_03.md: -------------------------------------------------------------------------------- 1 | ## パレットを開いて、Editor を選択解除するとパレットが閉じる 2 | 3 | 1. Editor をクリックする 4 | 2. Editor が選択されていること(背景色がベージュ) 5 | 3. Term モードにする 6 | 4. Entity を選択する 7 | 5. `Show label list editor [Q]`ボタンをクリックする 8 | 6. パレットがボタンの近くに開くこと 9 | 7. 一番上の input をクリックする 10 | 8. Editor が選択解除されること(背景色が白) 11 | 9. パレットが閉じること 12 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211109_04.md: -------------------------------------------------------------------------------- 1 | ## ダイアログを開いているときに Editor をクリックしてもパレットを閉じない 2 | 3 | ### 背景 4 | 5 | 1. jQueryUI ダイアログを開いた時に表示されるベールをクリックすると、Editor 外を選択したと判定して Editor の選択を解除していました 6 | 2. jQueryUI ダイアログは閉じた時に、ダイアログを開いたときに選択していた要素を選択し直す機能があります。このため一見わかりません 7 | 3. パレットはエディタの選択が解除された時点で、閉じます。 8 | 4. ベールが表示されているのに、その下にあるものが操作できるように見えます。これに違和感があります 9 | 5. 5.0.0 で、jQueryUI ダイアログのベールをクリックイベントを無視する対応しました 10 | 11 | ### -- 手段 -- 12 | 13 | 1. `Show label list editor [Q]`ボタンをクリックする 14 | 2. パレットが開くこと 15 | 3. アノテーション読込ダイアログを開く 16 | 4. ベールをクリックする 17 | 5. パレットが閉じないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211109_05.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity の色とラベル 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. 6.2.78 からブロックの Type 定義の色とラベルを BlockEntity に反映します 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. `block1`のラベルの背景色が赤系であること 12 | 3. `block1`のラベルの文言が`Label of block1`であること 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211109_06.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity は TypeGap を表示しない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. DenotationEntity の上側から Relation が出るため、上下に重なる DenotationEntity と DenotationEntity の間に TypeGap と呼ぶ隙間を空けています 7 | 3. BlockEntity は、一つの Span に複数の BlockEntity を持てません 8 | 4. 一つのヒットエリアの中に複数の BlockEntity が上下に並ぶことがなく、TypeGap は必要ありません 9 | 5. 6.2.81 で、BlockEntity の TypeGap をなくしました 10 | 6. TypeGap は Grid の`paddind-top`で実装されています 11 | 12 | ### -- 手段 -- 13 | 14 | 1. Editor1 を選択 15 | 2. `block1`に TypeGap がないこと 16 | 3. `block1`に Attribute を追加する 17 | 4. `block1`に TypeGap がないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211110_01.md: -------------------------------------------------------------------------------- 1 | ## A キーを押してエラーが起きない 2 | 3 | ### 背景 4 | 5 | 1. 6.1.5 で、Commander をオブジェクトからクラスに変更したときに、メソッド呼び出しの修正もれで、メソッドにレシバーが渡せず、エラーが起きるようになりました 6 | 2. 6.2.73 で対応しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. `A`キーを押す 11 | 2. エラーが起きないこと 12 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211110_02.md: -------------------------------------------------------------------------------- 1 | ## エンティティパレットの左右キーで Attribute タブを切り替える 2 | 3 | ### Block モード 4 | 5 | #### 背景 6 | 7 | 1. 6.2.77 で Block モードに対応しました 8 | 9 | #### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. Block モードにする 13 | 3. パレットを開く 14 | 4. 右キーを押す 15 | 5. Attribute タブが切り替わること 16 | 17 | ### Attribute がないとき 18 | 19 | #### 背景 20 | 21 | 1. 5.2.0 から左右キーでタブを切り替えられるようにしました 22 | 2. Attribute 定義がないときに、エンティティパレットを開いて右キーを押すとエラーが起きました 23 | 3. 6.2.70 で対応しました 24 | 25 | #### -- 手段 -- 26 | 27 | 1. Editor0 を選択 28 | 2. パレットを開く 29 | 3. 右キーを押す 30 | 4. エラーが起きないこと 31 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211110_03.md: -------------------------------------------------------------------------------- 1 | ## Relation をホバーする 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 で Block モードを追加しました 6 | 2. Block モードではホバーした Relation の線が太くなっていませんでした 7 | 3. 6.5.4 で対応しました 8 | 4. 6.7.1 でホバー時に矢印を大きさを変えるのをやめました 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Block モードにする 13 | 2. Relation を持つ Entity をホバーする 14 | 3. Relation のラベルが濃くなること 15 | 4. Relation の線が太くなること 16 | 5. Relation モードにする 17 | 6. Relation のラベルをホバーする 18 | 7. Relation のラベルが濃くなること 19 | 8. Relation の線が太くなること 20 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211110_04.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan をつくったときに TextBox の高さを調整する 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. BlockSpan をつくるとテキストが折り返されるため、テキストの高さが変わります。 7 | 3. 変わったテキストの高さに合わせて TextBox の高さを調整する必要があります。 8 | 4. 6.2.29 で対応しました。 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Editor4 を選択 13 | 2. Block モードにする 14 | 3. BlockSpan を追加する 15 | 4. テキストがエディタの下にはみ出ていかないこと 16 | 5. 追加した BlockSpan を削除する 17 | 6. テキストの下に余白ができないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211117_02.md: -------------------------------------------------------------------------------- 1 | ## DenotationEntity 編集後も選択状態を保持 2 | 3 | 1. Term-Simple モードにする 4 | 2. Type を選択する 5 | 3. Type を編集する 6 | 4. Type 編集後もラベルが選択されていること 7 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211118_01.md: -------------------------------------------------------------------------------- 1 | ## エンティティを選択中かつ Shift キーを押している間に、Span をマウスクリックするとエラーが起きないこと 2 | 3 | ### 背景 4 | 5 | 1. エンティティを選択中かつ Shift キーを押している間に、Span をマウスクリックするとエラーが起きます 6 | 2. 6.0.0 で対応しました。 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Term モードにする 11 | 2. エンティティを選択する 12 | 3. Shift キーを押しながら、Span をマウスクリック 13 | 4. エラーが起きないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211118_03.md: -------------------------------------------------------------------------------- 1 | ## Entity の見た目 2 | 3 | ### 背景 4 | 5 | 1. 6.2.28 で Entity のエンドポイントの表示をやめました。 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Entity の上に丸が表示されないこと 10 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211118_04.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーション読み込み 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 2. 6.4.149 でアノテーションとコンフィグレーションを同時に読み込んだ際に、扱うアノテーションのデータ形式をオブジェクトに変更しました。このときガード条件の追加をしなかったため、コンフィグレーションを単独で読み込むときに null 参照エラーが起きていました 7 | 3. 6.4.150 で対応しました 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor0 を選択 12 | 2. `Show label list editor [Q]`ボタンをクリックする 13 | 3. コンフィグレーション読込ダイアログを開く 14 | 4. URL 欄に`/dev/1_config.json`を入力し、`Open`ボタンを押して、サーバーから読み込む 15 | 5. パレットに`Cell`が表示されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211124_01.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーション読込ダイアログで ファイルから JSON でないファイルを読み込んだらエラーを alertify.js で表示 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 2. 5.3.0 でエラーが起きていました 7 | 3. 5.3.4 で対応 8 | 9 | #### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. `Show label list editor [Q]`ボタンをクリックする 13 | 3. コンフィグレーション読込ダイアログを開く 14 | 4. URL 欄に`development.html`を入力し、`Open`ボタンを押して、サーバーから読み込む 15 | 5. 右上に`http://localhost:8000/dist/demo/development.html is not a configuration file or its format is invalid.`と赤色のトースト表示がされること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211124_02.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーション読込ダイアログでテキストエリアに JSON でない文字列を入力して読み込んだらエラーを alertify.js で表示 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 2. 6.8.0 で機能を追加 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. `Show label list editor [Q]`ボタンをクリックする 12 | 3. コンフィグレーション読込ダイアログを開く 13 | 4. 適当に JSON ではない文字列をテキストエリアに記入し、`Open`ボタンを押して読み込む 14 | 5. 右上に`instant is not a configuration file or its format is invalid.`と赤色のトースト表示がされること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211124_03.md: -------------------------------------------------------------------------------- 1 | ## 隣の単語と単語の一部が Span になっているときに残りを Span にする 2 | 3 | ### Boundary Detection 有効時の動作 4 | 5 | 1. Editor1 を選択 6 | 2. 隣の単語と単語の一部までが Span にする(例:`Promoter met`) 7 | 3. 単語の残りの部分を選択する(例:`hylation`) 8 | 4. Span ができないこと 9 | 5. テキストの選択が解除されること 10 | 11 | ### Boundary Detection 無効時の動作 12 | 13 | 1. Editor5 を選択 14 | 2. 隣の単語と単語の一部までが Span にする(例:`Ribonucleic a`) 15 | 3. 単語の残りの部分を選択する(例:`cid`) 16 | 4. Span ができること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211124_04.md: -------------------------------------------------------------------------------- 1 | ### コンフィグレーション読込ダイアログで、URL が指定されていなければ Open ボタンを押せない 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. `Show label list editor [Q]`ボタンをクリックする 11 | 3. コンフィグレーション読込ダイアログを開く 12 | 4. URL が空の時は`Open`ボタンは無効 13 | 5. Local のファイルが選択されていない時は`Open`ボタンは無効 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211125_01.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーション読込ダイアログでテキストエリアに直接 JSON を記入し、コンフィグレーションを読み込むことができる 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 2. 6.8.0 で機能を追加 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. `Show label list editor [Q]`ボタンをクリックする 12 | 3. コンフィグレーション読込ダイアログを開く 13 | 4. `1_config.json`の内容をコピーし、`JSON`欄のテキストエリアにペーストする 14 | 5. `Open`ボタンを押して、JSON を読み込む 15 | 6. パレットに`Cell`が表示されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211125_02.md: -------------------------------------------------------------------------------- 1 | ## 読み込んだアノテーションの denotations に不正データが含まれていたら Validation Dialog に表示すること 2 | 3 | ### 背景 4 | 5 | 1. 6.2.20 ID が重複した denotations 検出機能を追加しました 6 | 2. 6.2.93 で`Dupulicated`の typo を修正 7 | 8 | ### -- 手段 -- 9 | 10 | 1. invalid.json を読み込む 11 | 2. Validation Dialog を表示すること 12 | 3. `Wrong range denotations.`に `T1`と`E2`が表示されること 13 | 4. `Out of text denotations.`に`begin` が `-2` で `end` が `0` の denotation と`E1`と`T1`と`E2`が表示されること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211130_01.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーション読込ダイアログで ドラッグアンドドロップでファイルを選択できる 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 2. 6.7.4 でドラッグアンドドロップでファイルを選択できる機能を追加 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. `Show label list editor [Q]`ボタンをクリックする 12 | 3. コンフィグレーション読込ダイアログを開く 13 | 4. `1_config.json`をドロップゾーン、またはダイアログ外の背景にドラッグアンドドロップする 14 | 5. `Open`ボタンを押して、ファイルを読み込む 15 | 6. パレットに`Cell`が表示されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211207_01.md: -------------------------------------------------------------------------------- 1 | ## 読み込んだアノテーションの denotations と blocks の ID 重複の検出 2 | 3 | ### 背景 4 | 5 | 1. 6.2.20 ID が重複した denotations 検出機能を追加しました 6 | 2. 6.2.21 で blocks のバリデーションを追加しました。 7 | 3. 6.2.93 で`Dupulicated`の typo を修正 8 | 4. 6.2.94 ID 重複用のテーブルを denotations と blocks で一つにまとめました 9 | 5. 6.2.95 で denotations と blocks の ID が重複している場合もチェックするようにしました。 10 | 11 | ### -- 手段 -- 12 | 13 | 1. invalid.json を読み込む 14 | 2. `Duplicated IDs in Denotations and Blocks.`に`T2`がみっつと`B3`がふたつ表示されること 15 | 3. `Duplicated IDs in Denotations and Blocks.`に`EB1`がふたつ表示されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211207_03.md: -------------------------------------------------------------------------------- 1 | ## アノテーションファイル中の BlockEntity 間の Relation を読み込める 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. アノテーションファイルに BlockEntity 間の Relation を記述しても、Relation の参照先として BlockEntity が見つからにためバリデーションエラーになっていました 7 | 3. 6.2.97 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. BlockEntity `B1`と`B2`の間に Relation が描画されていること 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211207_04.md: -------------------------------------------------------------------------------- 1 | ## アノテーションファイル中の BlockEntity 間の Attribute を読み込める 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. アノテーションファイルに BlockEntity の Attribute を記述しても、Attribute の参照先として BlockEntity が見つからにためバリデーションエラーになっていました 7 | 3. 6.2.99 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. BlockEntity `B1` の Attribute が描画されていること 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211207_05.md: -------------------------------------------------------------------------------- 1 | ## ブロックを含むアノテーションを読み込んだあとに他のアノテーションにを読み込めること 2 | 3 | ### 背景 4 | 5 | 1. アノテーションを読み込む際に、読み込み済みのブロック情報をクリアしていませんでした。 6 | 2. 読み込んだアノテーションと矛盾が生じてエラーが起きていました。 7 | 3. 6.2.4 で対応 8 | 9 | #### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. `prefix.json`を開く 13 | 3. エラーが起きないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211207_06.md: -------------------------------------------------------------------------------- 1 | ## 選択中の BlockSpan で DenotationEntity を隠さない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. ブロックスパンの位置を、実際の div 要素の位置より半行上に見せかけるために、背景用の div を追加しています 7 | 3. ブロックモードでは、ブロックをクリックできるように、背景用 div の z-index を加算していました 8 | 4. 背景用 div に選択中のスタイルを適用したときに DenotationEntity を隠していました 9 | 5. 6.2.37 で、背景用 div と別にマウス操作用の div を追加して、対応しました。 10 | 11 | ### -- 手段 -- 12 | 13 | 1. DenotationSpan の親になる BlockSpan を作成する 14 | 2. DenotationEntity の色が変わらないこと 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211207_07.md: -------------------------------------------------------------------------------- 1 | ## Block 要素の div をクリックしたら選択解除する 2 | 3 | ### 背景 4 | 5 | 1. BlockSpan は div としてレンダリングしています 6 | 2. BlockSpan の表示位置を半行上に見せかけるために、BlockSpan は背景とヒットエリアを別に持っています 7 | 3. BlockSpan 自体のマウスクリックイベントをハンドリングしていなかったため、BlockSpan の背景のすぐ下をクリックしたときに選択解除していませんでした。 8 | 4. 6.2.39 で対応しました 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Term モードにする 13 | 2. Span を選択する 14 | 3. Block のすぐ下をクリックする 15 | 4. Span が選択解除されること 16 | 5. Block モードにする 17 | 6. BlockSpan を選択する 18 | 7. BlockSpan のすぐ下をクリックする 19 | 8. BlockSpan が選択解除されること 20 | 9. Relation モードにする 21 | 10. Relation を選択する 22 | 11. BlockSpan のすぐ下をクリックする 23 | 12. Relation が選択解除されること 24 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_01.md: -------------------------------------------------------------------------------- 1 | ## コンフィグレーション読込ダイアログでテキストエリアに記入した JSON を、エディタを使って編集できる 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でコンフィグレーションの読込機能を追加しました 6 | 2. 6.8.0 で機能を追加 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. `Show label list editor [Q]`ボタンをクリックする 12 | 3. コンフィグレーション読込ダイアログを開く 13 | 4. `1_config.json`の内容をコピーし、`JSON`欄のテキストエリアにペーストする 14 | 5. `Edit`ボタンを押して、JSON エディタを展開する 15 | 6. エディタ上で`"id": "Cell"`を`"id": "cell"`に書き換える 16 | 7. `Open`ボタンを押して JSON を読み込む 17 | 8. パレットに`cell`が表示されること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_04.md: -------------------------------------------------------------------------------- 1 | ## ファイル読み込み時の認証情報入力 2 | 3 | ### 背景 4 | 5 | 1. 4.1.19 から Basic 認証付きの anntation.json の読み込みに対応しました。 6 | 7 | ### -- 手段 -- 8 | 9 | 1. アノテーション読込ダイアログを開く 10 | 2. を読み込む 11 | 3. 認証ダイアログが開くこと 12 | 4. ユーザーに`Jin-Dong Kim`、パスワードに`passpass`を設定してログインボタンを押す 13 | 5. private.json を読み込めること 14 | 6. 一度認証に成功するとブラウザがユーザーとパスワードを記憶します。もう一度試す場合はブラウザを再起動すること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_06.md: -------------------------------------------------------------------------------- 1 | ## ホバー 2 | 3 | ### 背景 4 | 5 | 1. 6.0.0 で Modification を廃止しました 6 | 2. 6.1.49 Entity のインスタンスだけでなく、ラベルをホバーしたときも Relation を強調するようにしました 7 | 3. 6.2.28 で Entity のエンドポイントの表示をやめました 8 | 4. 6.2.85 で Term モードで、Relation が強調されなくなっていました 9 | 5. 6.2.101 で対応しました 10 | 6. 6.7.0 で Relation のラベルを Entity と同じ表示形式(以降看板と呼ぶ)に変更しました 11 | 12 | ### 連動 13 | 14 | 1. Entity のラベルをホバーすると Relation も強調する 15 | 2. Relation のラベルをホバーすると Relation も強調する 16 | 17 | ### ホバー時の見た目の変化 18 | 19 | 1. Entity のラベルの div にシャドウ 20 | 2. Relation は Relation モードでのみラベルの div にシャドウ 21 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_07.md: -------------------------------------------------------------------------------- 1 | ## コピー&ペースト 2 | 3 | ### 背景 4 | 5 | 1. 6.0.0 で Modification を廃止しました。 6 | 2. 6.1.1 で一つの denotation を一つのエンティティに表示することしました。 7 | 8 | ### span 9 | 10 | 1. Editor1 を選択 11 | 2. Attribute と Relation を持つ Entity のある Span を選択してコピーする 12 | 3. 他の Span を選択して貼り付ける 13 | 4. 選択した Span の全ての Entity と Attribute が、対象 Span に張り付く 14 | 5. Relation はコピーされない 15 | 16 | ### Entity 17 | 18 | 1. Editor1 を選択 19 | 2. Attribute と Relation を持つ Entity のある Entity を選択してコピーする 20 | 3. 他の Span を選択して貼り付ける 21 | 4. 選択した全ての Entity とその Attribute、対象 Span に張り付く 22 | 5. Relation はコピーされない 23 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_08.md: -------------------------------------------------------------------------------- 1 | ## リサイズすると Grid を移動する 2 | 3 | ### 背景 4 | 5 | 1. 4.1.10 の修正中に、リサイズしても、二段目より上の Type が横に移動するだけで縦に移動しなくなりました。 6 | 2. 4.4.3 の修正中に、Grid だけ移動して、Relation が移動しなくなりました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. ウインドウをリサイズする 11 | 2. Grid が Span に追従して移動すること 12 | 3. Relation が Grid に追従して移動すること 13 | 14 | ### Relation を選択してリサイズする 15 | 16 | 1. Relation モードにする 17 | 2. Relation を選択 18 | 3. リサイズして選択した Relation を移動する 19 | 4. 矢印が小さくならないこと 20 | 5. ホバーしても、線が細くならないこと 21 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_09.md: -------------------------------------------------------------------------------- 1 | ## タイプ変更を Undo したとき、変更対象を選択しない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 7 | ### DenotationEntity 8 | 9 | 1. Term モードにする 10 | 2. DenotationEntity を選択 11 | 3. タイプを変更する 12 | 4. 戻す 13 | 5. 選択されないこと 14 | 15 | ### BlockEntity 16 | 17 | 1. Block モードにする 18 | 2. BlockEntity を選択 19 | 3. タイプを変更する 20 | 4. 戻す 21 | 5. 選択されないこと 22 | 23 | ### Relation 24 | 25 | 1. Relation モードにする 26 | 2. Relation を選択 27 | 3. タイプを変更する 28 | 4. 戻す 29 | 5. 選択されないこと 30 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211208_10.md: -------------------------------------------------------------------------------- 1 | ## 外部 JavaScript で Editor を初期フォーカスできること 2 | 3 | 1. を開く 4 | 2. Editor1 が選択されていること(背景色がベージュ) 5 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211209_01.md: -------------------------------------------------------------------------------- 1 | ## 起動直後 2 | 3 | ### 背景 4 | 5 | 1. `4.4.0`からデフォルト文字列を表示します 6 | 2. annotation がない場合も、Editor はサイズがありクリックできます 7 | 3. 起動時に一番上の Editor を選択する機能を消します 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor7 が選択されていないこと(背景色が白い) 12 | 2. Editor7 をクリック 13 | 3. Editor7 が選択されること(背景色がベージュ) 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211209_02.md: -------------------------------------------------------------------------------- 1 | ## Span は必ず Entity を持つ 2 | 3 | ### Entity を自動作成 4 | 5 | #### 背景 6 | 7 | 1. 4.1.8 で Entity につける id の prefix を`E`から`T`に変えました 8 | 2. 6.2.0 からブロック機能を追加 9 | 10 | #### -- 手段 -- 11 | 12 | 1. Term モードにする 13 | 2. DenotationSpan を作成する 14 | 3. default の Type の Entity ができること 15 | 4. Entity の id が`T`で始まること 16 | 5. Block モードにする 17 | 6. BlockSpan を作成する 18 | 7. default の Type の Entity ができること 19 | 8. Entity の id が`T`で始まること 20 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211209_03.md: -------------------------------------------------------------------------------- 1 | ## コピーした Entity を削除してから貼付ける 2 | 3 | 1. Entity を選択する 4 | 2. コピーする 5 | 3. 削除する 6 | 4. 別の Span を選択する 7 | 5. 貼付ける 8 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211214_01.md: -------------------------------------------------------------------------------- 1 | ## 特殊な Type 文字列 2 | 3 | ### ドメインな文字列 4 | 5 | #### 背景 6 | 7 | 1. Type の Value に url を指定した場合は短縮してラベルに表示します 8 | 2. Type が`http://pubmed.org/`のときにディレクトリ名を取得しようとして空文字を取得していた 9 | 3. ラベルが空だと正しくレンダリングできません 10 | 4. 4.1.8 で対応しました 11 | 12 | #### -- 手段 -- 13 | 14 | 1. Editor1 を選択 15 | 2. Type `http://pubmed.org/`の表示が`pubmed.org`になること 16 | 17 | ### ドメインが localhost 18 | 19 | 1. 既存の Entity を選択する 20 | 2. Type の Value を`http://localhost:8000/abc`に変更する 21 | 3. Type の表示が abc になること 22 | 23 | ### http で始まる URL ではない文字列 24 | 25 | 1. 既存の Entity を選択する 26 | 2. Type の Value を`http://hoge`に変更する 27 | 3. Type の表示が`http://hoge`になること 28 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211215_02.md: -------------------------------------------------------------------------------- 1 | ## 未保存変更があるときに、別のアノテーションを読み込もうとすると確認ダイアログを表示 2 | 3 | ### 背景 4 | 5 | 1. 保存していない変更があるか状態を持っています 6 | 2. 変更があるときに load しようとすると確認ダイアログを表示します 7 | 3. 一度保存すると変更状態をリセットします 8 | 4. 確認ダイアログを表示しなくなります 9 | 10 | ### -- 手段 -- 11 | 12 | 1. 変更する 13 | 2. 読込む 14 | 3. 確認ダイアログが出る 15 | 4. キャンセルする 16 | 5. 保存する 17 | 6. 読込む 18 | 7. 確認ダイアログが出ない 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211215_03.md: -------------------------------------------------------------------------------- 1 | ## Attribute インスタスがあるアノテーション読み込んでから、Attribute 定義がないアノテーションを読み込む 2 | 3 | ### 背景 4 | 5 | 1. アノテーションを読み込むときにコンフィグレーションも読み直しています 6 | 2. コンフィグレーションを読みなおしたときにすべての Entity をレンダリングしなおしています 7 | 3. Attribute を持つ Entity をレンダリングするときに Attribute の表示名を取得しようとします 8 | 4. 6.4.90 で Attribute の表示名を取得するときに、Attribute 定義がなかったときにエラーが起きるようにしました 9 | 5. コンフィグレーションがリセット済みのため Attribute 定義が存在しないためエラーが起きます 10 | 6. 6.4.141 で対応しました 11 | 12 | ### -- 手段 -- 13 | 14 | 1. Editor1 を選択 15 | 2. アノテーション読込ダイアログを開く 16 | 3. ローカルファイルから`private.json`を読み込む 17 | 4. エラーが起きないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211215_04.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity 編集ダイアログを開く 2 | 3 | ### Change Label[W]ボタン 4 | 5 | 1. Block モードにする 6 | 2. BlockEntity を選択する 7 | 3. `Change Label[W]`ボタンを押す 8 | 4. 編集ダイアログが開くこと 9 | 10 | ### W キー 11 | 12 | 1. Block モードにする 13 | 2. BlockEntity を選択する 14 | 3. `W`キーを押す 15 | 4. 編集ダイアログが開くこと 16 | 17 | ### コンテキストメニュー 18 | 19 | 1. Block モードにする 20 | 2. BlockEntity を選択する 21 | 3. 右クリックする 22 | 4. コンテキストメニューが開くこと 23 | 5. コンテキストメニューの 24 | 6. `Change Label[W]`ボタンを押す 25 | 7. 編集ダイアログが開くこと 26 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211215_05.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan にはひとつの BlockEntity しか追加できない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.110 で、BlockSpan にはひとつの BlockEntity しか追加できなくしました 6 | 7 | ### -- 手順 -- 8 | 9 | 1. Editor1 を選択 10 | 2. Block モードにする 11 | 3. BlockSpan を選択 12 | 4. `E`キーを押す 13 | 5. BlockEntity が追加されないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211215_07.md: -------------------------------------------------------------------------------- 1 | ## 該当 Attribute を持つアイテムを選択しているときに、パレットの Attribute 削除ボタンを有効にする 2 | 3 | ### 背景 4 | 5 | 1. 6.4.58 で無効理由を title タグで記述します 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. Term モードにする 11 | 3. Attribute のない Entity を一つ選択する 12 | 4. `q` キーを押してパレットを開く 13 | 5. `denote` タブを選ぶ 14 | 6. `remove form`ボタンが無効であること 15 | 7. title が`None of the selected items has this attribute.`であること 16 | 8. `add to`ボタンを押す 17 | 9. `remove form`ボタンが有効になること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211216_01.md: -------------------------------------------------------------------------------- 1 | ## Selection Attribute 定義の Value の label、color 変更 2 | 3 | ### 背景 4 | 5 | 1. 5.2.0 から Entity パレットで Selection Attribute の Value が編集出来るようになりました。 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. Term モードにする 11 | 3. `Show label list editor [Q]`ボタンをクリックする 12 | 4. `denote`タブを選択 13 | 5. `Cell`の`Edit this value`ボタンをクリックする 14 | 6. `label`欄を変更する 15 | 7. `color`欄を変更する 16 | 8. `OK`ボタンを押す 17 | 9. パレットの Value の値が更新されるここと 18 | 10. エンティティ`E1:a:b`の Attribute のラベルと色が更新されるここと 19 | 11. すべてもどす 20 | 12. すべてやり直す 21 | -------------------------------------------------------------------------------- /userAcceptanceTest/20211224_03.md: -------------------------------------------------------------------------------- 1 | ## DenotationEntity を選択して編集ダイアログを開く 2 | 3 | ### Change Label[W]ボタン 4 | 5 | 1. Term モードにする 6 | 2. DenotationEntity を選択する 7 | 3. `Change Label[W]`ボタンを押す 8 | 4. 編集ダイアログが開くこと 9 | 10 | ### W キー 11 | 12 | 1. Term モードにする 13 | 2. DenotationEntity を選択する 14 | 3. `W`キーを押す 15 | 4. 編集ダイアログが開くこと 16 | 17 | ### コンテキストメニュー 18 | 19 | 1. Term モードにする 20 | 2. DenotationEntity を選択する 21 | 3. 右クリックする 22 | 4. コンテキストメニューが開くこと 23 | 5. コンテキストメニューの 24 | 6. `Change Label[W]`ボタンを押す 25 | 7. 編集ダイアログが開くこと 26 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220105_01.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan のヒットエリアのタイトルに BlockSpan の ID を表示 2 | 3 | ### 背景 4 | 5 | 1. 6.4.62 で対応 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. BlockSpan のヒットエリアのタイトルに Span の ID が`begin-end`形式で入っていること 11 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220106_01.md: -------------------------------------------------------------------------------- 1 | ## 連続した BlockSpan の間に空行が挟まらない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 で Block モードを追加しました 6 | 2. BlockSpan を div で表現しているため、div 間に改行が挟まれ、1 行余計に隙間が空いていました 7 | 3. 6.2.114 で、BlockSpan に`display: inline-block`と`width: 100px`を指定して、改行しつつ、余計な空行は挟まらないようにしました 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. `block1`と`block2`の間に隙間がないこと 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220106_05.md: -------------------------------------------------------------------------------- 1 | ## Relation の編集 2 | 3 | ### 背景 4 | 5 | 1. 6.0.0 で Modification を廃止しました。 6 | 7 | ### 作る、変える、消す 8 | 9 | 1. Span を2つ作る 10 | 2. Relation モードにする 11 | 3. Relation を作る 12 | 4. 作った Relation が選択される 13 | 5. Relation の type を変更する 14 | 6. Relation の線が細くならないこと 15 | 7. 作った Relation を消す 16 | 8. Entity を片方消す 17 | 9. Span が残っていたら Span を消す(Span の Entity がゼロ個になると、Span は自動的に削除されます) 18 | 10. 全て戻す 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220112_02.md: -------------------------------------------------------------------------------- 1 | ## Attribute 定義の順序変更 2 | 3 | ### 背景 4 | 5 | 1. 5.3.6 で、パレットの Attribute タブをドラッグアンドドロップして、Attribute 定義の順序を変更する機能を追加しました。 6 | 2. Attribute 定義の最大数を超えているときに、プラスタブを表示しません。 7 | 3. このとき同時に最後尾へのドロップができなくなっていました。 8 | 4. 6.4.88 で対応しました。 9 | 10 | ### -- 手順 -- 11 | 12 | 1. Editor1 を選択 13 | 2. Term モードにする 14 | 3. `Q`キーを押してパレットを開く 15 | 4. `denote`タブを選択する 16 | 5. `denote`タブをドラッグして、`warning`タブの前の矢印の上に移動する、タブの左側に空間ができること 17 | 6. ドロップする 18 | 7. `denote`タブが、`warning`タブの前に移動すること 19 | 8. Z キーを押す 20 | 9. `denote`タブが先頭に戻ること 21 | 10. a~p までの Attribute 定義を追加する 22 | 11. o を p の後ろにドロップする 23 | 12. `o`タブが`p`タブの後ろに移動すること 24 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220112_03.md: -------------------------------------------------------------------------------- 1 | ## 別の annotatian を開いて高さが再計算されること 2 | 3 | ### 背景 4 | 5 | 1. annotation によって行数が変わるので高さを再計算しなくてはいけません。 6 | 7 | ### -- 手段 -- 8 | 9 | 1. 1_annotations.json を開く 10 | 2. multi_tracks.json を開く 11 | 3. 高さが再計算されること 12 | 4. 下側の隙間が狭いこと 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220112_04.md: -------------------------------------------------------------------------------- 1 | ## DenotationEntity 編集ダイアログの編集キャンセル 2 | 3 | ### 閉じるボタン 4 | 5 | 1. Term モードにする 6 | 2. DenotationEntity を選択する 7 | 3. `W`キーを押す 8 | 4. 編集ダイアログが開くこと 9 | 5. 文字を変更する 10 | 6. `X`ボタンを押す 11 | 7. DenotationEntity の id が変わらないこと 12 | 13 | ### Esc キー 14 | 15 | 1. Term モードにする 16 | 2. DenotationEntity を選択する 17 | 3. `W`キーを押す 18 | 4. 編集ダイアログが開くこと 19 | 5. 文字を変更する 20 | 6. `Esc`キーを押す 21 | 7. DenotationEntity の id が変わらないこと 22 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220112_05.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan のヒットエリア 2 | 3 | ### 背景 4 | 5 | 1. Block モードでは、BlockSpan のヒットエリアに背景色が着いていました 6 | 2. 6.4.63 で、Block モード以外のモードでも、背景色を薄くつける対応をしました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. BlockSpan のヒットエリアに背景色があること 13 | 4. Block モードにする 14 | 5. BlockSpan のヒットエリアに背景色が濃くなること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220112_06.md: -------------------------------------------------------------------------------- 1 | ## 長い文字列を含むアノテーションを開く 2 | 3 | ### 背景 4 | 5 | 1. Google chrome と Safari は 65536 文字以上のテキストを複数の text node に分割します。 6 | 2. span の開始位置の offset が text node の範囲を越えることがあります。 7 | 3. text node の中に span をつくる場所が見つからずエラーになっていました。 8 | 4. 6.0.4 で対応しました。 9 | 10 | ### 手段 11 | 12 | 1. を読み込む 13 | 2. エラーが起きないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220112_07.md: -------------------------------------------------------------------------------- 1 | ## Entity に HTML タグを含むラベルを設定したときにラベルの定義に HTML エスケープされた文字列が設定されないこと 2 | 3 | ### 背景 4 | 5 | 1. ラベルは編集ダイアログの HTML 要素に innerText を使って設定され、その値を取得するときに innerHTML を使っていたため、HTML タグを含むラベルを設定した際に、HTML エスケープされていました。 6 | 2. 6.4.18 で対応しまた。 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. Entity を選択する 13 | 4. `w`キーを押して Entity 編集ダイアログを開く 14 | 5. `Value:`欄に`HTML`を入力する 15 | 6. 候補から`HTML tag label`を選択し、確定する 16 | 7. `q`キーを押してパレットを開く 17 | 8. `Save Configurations`ダイアログを開く 18 | 9. `entity types`に`HTML tag label`の変更がないこと 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220118_02.md: -------------------------------------------------------------------------------- 1 | ## line-height 変更 2 | 3 | ### 背景 4 | 5 | 1. 4.1.8 で text−box の下の隙間を小さくした 6 | 2. 4.1.16 の開発中にモジュール読み込み構文の修正漏れでエラーを起こしていました。 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Seting ダイアログを開く 11 | 2. line-height を変更する 12 | 3. 高さが再計算されること 13 | 4. 下側の隙間が狭いこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220119_01.md: -------------------------------------------------------------------------------- 1 | ## 先頭の Span を後ろから縮めて消したときにエラーが起きない 2 | 3 | ### 背景 4 | 5 | 1. 6.1.53 で、追加した必須パラメータのアサーションに 0 も引っかかって発生 6 | 2. 6.3.3 で対応 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. 最初の Span を後ろから縮めて消す 12 | 3. エラーが起きないこと 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220119_02.md: -------------------------------------------------------------------------------- 1 | ## 該当 Attribute のない Entity を選択しているときに、ショートカットキーから Attribute インスタンスを削除しようとしたら警告を表示する 2 | 3 | ### 背景 4 | 5 | 1. 6.4.58 で無効理由を title タグで記述します 6 | 2. ショートカットキーから削除できないときも、同様の情報をアラート表示します。 7 | 3. 6.4.124 で対応しました 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. Term モードにする 13 | 3. Attribute のない Entity を一つ選択する 14 | 4. `shift`キーを押しながら、`1`キーを押す 15 | 5. `None of the selected items has this attribute.`がアラート表示されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220119_03.md: -------------------------------------------------------------------------------- 1 | ## アノテーション保存時にメッセージを alertify.js で表示 2 | 3 | ### 背景 4 | 5 | 1. ステータスバーにメッセージを表示していました。 6 | 2. Editor が大きいと隠れていた 7 | 3. トーストを使って表示します 8 | 9 | ### -- 手段 -- 10 | 11 | 1. annotation を保存する 12 | 2. 右上に`annotation saved`と緑色のトースト表示がされること 13 | 3. サーバを落とす 14 | 4. サーバに annotation を保存する 15 | 5. 右上に`could not save`と赤色のトースト表示がされること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220119_04.md: -------------------------------------------------------------------------------- 1 | ## shift を押して Span を選択 2 | 3 | ### コピー 4 | 5 | 1. Term モードにする 6 | 2. shift で複数の Span をえらぶ 7 | 3. コピーする 8 | 4. 貼り付けする 9 | 5. 選択してる Span の全ての Entity がコピーされること 10 | 11 | ### 削除 12 | 13 | 1. Term モードにする 14 | 2. shift で複数の Span をえらぶ 15 | 3. 削除する 16 | 4. 選択してる Span が全て削除されること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220119_06.md: -------------------------------------------------------------------------------- 1 | ## inline で連続した空白を含む annotation を開けること 2 | 3 | ### 背景 4 | 5 | 1. inline の annotation の text に、連続した空白が含まれていた場合、埋め込んだ時点で、1つの空白にまとめられていた 6 | 2. annotation の texte に、連続した空白が含まれていた場合、Editor 上に表示する文字列ので、1つの空白にまとめられていた 7 | 3. `textae-editor`クラスと、`textae-editor__body__text-box__paragraph-margin`クラスに、`white-space: pre`スタイルを指定が必要 8 | 4. v4.5.7 で対応 9 | 10 | ### -- 手段 -- 11 | 12 | 1. editor9 を選択 13 | 2. `stomach`の Span がズレていないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220121_02.md: -------------------------------------------------------------------------------- 1 | ## 兄弟 Span を親 Span にする 2 | 3 | ### 背景 4 | 5 | 1. 5.2.1, 5.2.2 で並んだ兄弟 Span の片方を伸ばすして、端を共有する親子 Span にする操作を便利にしました 6 | 2. 以前は、一度両側がはみ出た大きな親 Span にしてから、はみ出た部分を縮める操作が必要でした 7 | 3. 5.2.1 で、親にしたい Span を選択して、伸ばして子にしたい Span の上で mouse up して、端を共有する親 Span にできるようになりました 8 | 4. 5.2.2 で、親にしたい Span を選択して、伸ばして子にしたい Span の上にブラウザのセレクションが有る状態で、テキスト間の空白領域で mouse up して、端を共有する親 Span にできるようになりました 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Term モードにする 13 | 2. Span を作る 14 | 3. 兄弟になる Span を作る 15 | 4. 片方の Span をもう片方の Span を覆う範囲に広げる 16 | 5. 親子 Span になること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220121_03.md: -------------------------------------------------------------------------------- 1 | ## annotation なし 2 | 3 | ### 背景 4 | 5 | 1. 開発中は annotation なしで開きません。エラーの見落としが多いです。 6 | 2. `4.4.0`から、annotation がない時はデフォルト文字列を表示します。 7 | 3. `4.5.0`から、html 属性で`mode="edit"`をつけない場合は View モードになり、View モードの場合はコントロールバーを表示しなくしました。 8 | 9 | ### Edit モード 10 | 11 | 1. Editor7 を選択 12 | 2. Editor 中に`Currently, the document is empty. Use the "import" button or press the key "i" to open a document with annotation.`が表示されること 13 | 3. エディタを選択するとコントロールバーが表示されること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220125_01.md: -------------------------------------------------------------------------------- 1 | ## 連続した空白の扱い 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 アノテーションテキスト中の連続した空白をまとめずに描画しています。 6 | 2. Span をつくると、Span 内では連続した空白をまとめていました。 7 | 3. 6.1.1 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. editor9 を選択 12 | 2. `stomach ache`を Span にする 13 | 3. 単語の間の連続した空白がまとまらないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220125_03.md: -------------------------------------------------------------------------------- 1 | ## Attribute 定義がないときにパレットが開ける 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 で Attitude を追加しました 6 | 2. 6.4.91 で、6.4.88 で Attribute 定義がないときにパレットを開くとエラーが起きていたのを直しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. Term モードにする 12 | 3. `q` キーを押してパレットを開く 13 | 4. エラーが起きないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220127_02.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan は親 Span を持たない 2 | 3 | ### 背景 4 | 5 | 1. BlockSpan はなんらかの Span の子になることはありません。Block モードで、他の Span の子 BlockSpan を作成できていました。 6 | 2. 6.3.7 で対応しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Term モードにする 11 | 2. 複数単語を選択して DenotationSpan を作成する 12 | 3. Block モードにする 13 | 4. 作成した DenotationSpan 中の 1 単語を選択する 14 | 5. BlockSpan が作られないこと 15 | 6. 文字列の選択が解除されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220202_01.md: -------------------------------------------------------------------------------- 1 | ## Entity パレットのタイトルを折り返さない 2 | 3 | ### 背景 4 | 5 | 1. Attribute 定義がたくさんあるとき、EntityPallet のタイトルが折り返していました。 6 | 2. 6.3.12 でタイトルに最低幅を設定しました。 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. `Q`キーを押して、EntityPallet を開く 13 | 4. 左上のタイトル`Entity Configuration`が折り返さないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220202_02.md: -------------------------------------------------------------------------------- 1 | ## ステータスバーの表示非表示 2 | 3 | ### 背景 4 | 5 | 1. 4.1.6 でステータスバーのデフォルト非表示になりました 6 | 2. status_bar オプションで切り替えます 7 | 3. 値は on と off の2つです 8 | 9 | ### -- 手段 -- 10 | 11 | 1. 属性の status_bar に on を指定するとステータスバーが表示されること(editor1) 12 | 2. 属性の status_bar を指定しないとステータスバーが表示されないこと(editor2) 13 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220202_03.md: -------------------------------------------------------------------------------- 1 | ## スタイルで行の高さを指定できること 2 | 3 | ### 背景 4 | 5 | 1. 4.1.14 で行の高さをスタイルで上書きできるようになりました 6 | 2. 6.0.0 で padding-top と height が設定されなくなりました 7 | 3. 6.1.45 で対応 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor2 を選択する 12 | 2. `.textae-editor__body__text-box`の line-height が`14px`であること 13 | 3. `.textae-editor__body__text-box`の padding-top が`7px`であること 14 | 4. `.textae-editor__body__text-box`の height が`48px`であること 15 | 5. Setting ダイアログを開く 16 | 6. Line Height の値が 14 であること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220202_05.md: -------------------------------------------------------------------------------- 1 | ## 行の高さを変更して annotation を読み直すと行が再計算されること 2 | 3 | ### 背景 4 | 5 | 1. ファイルを読み直したときに行の高さを再計算していませんでした 6 | 2. 4.4.3 で再計算することにしました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Setting ダイアログで行の高さを変更する 11 | 2. 行の高さが変わること 12 | 3. Grid の位置が変わること 13 | 4. アノテーション読込ダイアログを表示 14 | 5. URL からアノテーションを読み込む 15 | 6. 行の高さが再計算されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220203_02.md: -------------------------------------------------------------------------------- 1 | ## Entity の Type 定義の label 属性 2 | 3 | ### 背景 4 | 5 | 1. 4.3.0 から config に Entity の Type に label を定義できるようになりました 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Edtor1 を選択 10 | 2. Term モードにする 11 | 3. Entity を選択する 12 | 4. `w`キーを押して、Type を`http://www.yahoo.co.jp`に変更します 13 | 5. Type の表示が`Regulation`になること 14 | 6. V アイコンを押して View モードに切り替える 15 | 7. Type のラベルがリンクになること 16 | 8. リンクをクリックすると`http://www.yahoo.co.jp`が開くこと 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220207_01.md: -------------------------------------------------------------------------------- 1 | ## Editor の自動選択 2 | 3 | ### 背景 4 | 5 | 1. 1 画面に複数のエディタを組み込めるように、エディタの選択は外部スクリプトで行っています 6 | 2. 5.2.4 までは setTimeout を使って、選択時間を遅らせて自動選択していました 7 | 3. textae の focus イベントリスナーは load イベントでバインドしています 8 | 4. html の読み込みに時間がかかった場合、textae 側が listen する前に、外部スクリプトが focus し自動選択に失敗していました 9 | 5. 5.2.5 で、外部スクリプトを load イベントで実行することで確実にエディタが自動選択されるようになりました 10 | 11 | ### -- 手段 -- 12 | 13 | 1. Editor0 が自動選択されること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220207_02.md: -------------------------------------------------------------------------------- 1 | ## 既存の要素を消す 2 | 3 | ### メイン 4 | 5 | 1. Relation モードにする 6 | 2. Relation を消す 7 | 3. Entity を消す 8 | 4. Term モードにする 9 | 5. Span を消す 10 | 6. Relation のある Span を消す 11 | 7. Relation のある Entity を消す 12 | 8. 全て戻す 13 | 9. 選択されないこと 14 | 10. やり直す 15 | 11. 全て戻してからやり直すのを 4 回繰り返す 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220207_03.md: -------------------------------------------------------------------------------- 1 | ## ラベルの定義に HTML タグが含まれているとき、HTML エスケープした文字列をオートコンプリートの候補として表示すること 2 | 3 | ### 背景 4 | 5 | 1. オートコンプリートの候補には Type 定義の`id`と`label`を表示しています。 6 | 2. HTML エスケープしていないため、`label`に HTML タグを含む Type を定義すると、オートコンプリートの候補に任意の HTML タグを挿入することが可能です。 7 | 3. 6.4.24 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. Term モードにする 13 | 3. Entity を選択する 14 | 4. `w`キーを押して Entity 編集ダイアログを開く 15 | 5. `Value:`欄に`HTML`を入力する 16 | 6. 候補に赤字の`Red color HTML label`ではなく、`Red color HTML label...`が表示されること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220208_01.md: -------------------------------------------------------------------------------- 1 | ## Entity と Relation を同時に選択した時の Label 編集は Relation の Label を表示 2 | 3 | ### 背景 4 | 5 | 1. SelectionModel は id だけを保持しています 6 | 2. id は外部(anntation.js)から指定されることがあります 7 | 3. id だけでは何を選択しているかわかりません 8 | 4. SelectionModel は Entity と Relation に分かれています 9 | 5. 編集モードに応じて参照する SelectionModel を切り替えます 10 | 6. 6.2.25 から SelectionModel でアノテーションモデルインスタスへの参照を保持するようになりました 11 | 12 | ### -- 手段 -- 13 | 14 | 1. Relation モードにする 15 | 2. Entity を選択する 16 | 3. Ctrl を押しながら Relation を選択する 17 | 4. Label を編集する 18 | 5. `Value/Label`欄に Relation の pred の文字列が表示されること 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220210_02.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity にパレットから Attribute を追加 2 | 3 | ### 背景 4 | 5 | 1. 6.2.71 で Block モードでパレットが開けるようになりました 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Editor1 を選択 10 | 2. Block モードにする 11 | 3. Attribute を持たない BlockEntity を選択する 12 | 4. パレットを開く 13 | 5. denote タブを選択する 14 | 6. `add to`ボタンを押す 15 | 7. Attribute が追加されること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220215_02.md: -------------------------------------------------------------------------------- 1 | ## Term モードでテキスト上で mousedown して StyleSpan 上で mouseup してエラーが起きない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.43 で発生 6 | 2. 6.3.19 で対応 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. テキスト上で mousedown して、右方向の、StypleSpan 上で mouseup する 13 | 4. エラーが起きないこと 14 | 5. テキスト上で mousedown して、左方向の、StypleSpan 上で mouseup する 15 | 6. エラーが起きないこと 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220215_04.md: -------------------------------------------------------------------------------- 1 | ## アノテーションが無いときに行の高さが 41px になること 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 でアノテーションが無いときに行の高さがなくなっていました 6 | 2. 5.2.4 で対応しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor7 を選択する 11 | 2. `.textae-editor__body__text-box`の line-height が`41px`であること 12 | 3. `.textae-editor__body__text-box`の padding-top が`20.5px`であること 13 | 4. Setting ダイアログを開く 14 | 5. Line Height の値が 41 であること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220216_02.md: -------------------------------------------------------------------------------- 1 | ## URL からアノテーション読込 2 | 3 | ### URL が指定されていなければ Open ボタンを押せない 4 | 5 | 1. アノテーション読込ダイアログを開く 6 | 2. URL 欄が空の時は`Open`ボタンは無効 7 | 3. Local のファイルが選択されていない時は`Open`ボタンは無効 8 | 9 | ### 存在しないアノテーションを読み込む 10 | 11 | #### 背景 12 | 13 | 1. 読み込み失敗時のメッセージが素っ気なかった 14 | 2. 4.1.12 から優しくなりました 15 | 16 | #### -- 手段 -- 17 | 18 | 1. 存在しないファイルを読み込む 19 | 2. 赤いトーストが表示されること 20 | 3. `Could not load the file from the location you specified.:`が表示されること 21 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220216_03.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan をつくったときにドキュメントの最上部までスクロールしない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. BlockSpan を作ったとき、同時に BlockEntity を作成し両者を選択します 7 | 3. エンティティを選択する際に、ラベルにフォーカスをあてて、選択しているエンティティをブラウザの表示領域にスクロールインします 8 | 4. BlockEntity を作成する際、位置の基準となる Div の位置がブラウザ上で確定するするのが遅いため、一瞬ドキュメントの最上部に配置されます 9 | 5. このときフォーカスするとブラウザがドキュメントの最上部までスクロールします 10 | 6. 6.2.49 で、BlockEntity を選択する際に、位置が確定していなければ、確定後にフォーカスする処理をいれ、対応しました 11 | 12 | ### -- 手段 -- 13 | 14 | 1. Editor4 を選択 15 | 2. Block モードにする 16 | 3. BlockSpan を追加する 17 | 4. ブラウザがドキュメントの最上部までスクロールしないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220216_05.md: -------------------------------------------------------------------------------- 1 | ## パレットのスクロールバー 2 | 3 | ### 背景 4 | 5 | 1. パレットに、スクロールが必要ない場合も、横スクロールバーが表示されていました 6 | 2. 6.4.75 で横スクロールバーの常時表示をやめました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. パレットを開く 11 | 2. パレットの下部に横スクロールバーが表示されないこと 12 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220217_01.md: -------------------------------------------------------------------------------- 1 | ## Block モードで、Body クリックでパレットが閉じる 2 | 3 | ### 背景 4 | 5 | 1. 6.2.75 で Block モードに対応しました 6 | 2. BlockSpan のクリックイベントにパレットを閉じる処理がぬけていました 7 | 3. 6.4.61 で対応 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Block モードにする 12 | 2. `Show label list editor [Q]`ボタンをクリックする 13 | 3. パレットが開くこと 14 | 4. 行間をクリックする 15 | 5. パレットが閉じること 16 | 6. BlockSpan のすぐ上をクリックする 17 | 7. パレットが閉じること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220222_01_mouse.md: -------------------------------------------------------------------------------- 1 | ## Term モードで DenotationSpan 上で mousedown して StyleSpan 上で mouseup してエラーが起きない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.43 で発生 6 | 2. 6.3.20 で対応 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. DenotationSpan 上で mousedown して、StypleSpan 上で mouseup する 13 | 4. エラーが起きないこと 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220222_02_mouse.md: -------------------------------------------------------------------------------- 1 | ## Term モードで BlockSpan 上で mousedown して StyleSpan 上で mouseup してエラーが起きない 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 で関数名を Typo して発生 6 | 2. 6.3.18 で対応 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Block モードにする 12 | 3. StyleSpan の隣に BlockSpan を作成する 13 | 4. Term モードにする 14 | 5. BlockSpan 中のテキスト上で mousedown して、StypleSpan 上で mouseup する 15 | 6. エラーが起きないこと 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220302_01.md: -------------------------------------------------------------------------------- 1 | ## config の PushButton 設定 2 | 3 | ### 背景 4 | 5 | 1. 6.1.5 から config で自動保存、境界検出、行の高さ自動調整の ON/OFF を設定できるようになりした 6 | 7 | ### config の指定がない場合 8 | 9 | 1. Editor0 の自動保存が無効であること 10 | 2. Editor0 の行の高さ自動調整が有効であること 11 | 3. Editor0 の境界検出が有効であること 12 | 13 | ### アノテーションファイル内に cofig がある場合 14 | 15 | 1. Editor1 の自動保存が有効であること 16 | 2. Editor1 の行の高さ自動調整が無効であること 17 | 3. Editor1 の境界検出が有効であること 18 | 19 | ### config の指定があるが中身で指定がない場合 20 | 21 | 1. Editor2 の自動保存が無効であること 22 | 2. Editor2 の行の高さ自動調整が有効であること 23 | 3. Editor2 の境界検出が有効であること 24 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220302_02.md: -------------------------------------------------------------------------------- 1 | ## Entity を作成すると自動選択 2 | 3 | ### 背景 4 | 5 | 1. 新規 Entity の ID を anntotian.json の dennotation の id から連番で降っています 6 | 2. T ではじまる ID を生成した ID として扱っていました 7 | 3. annotation.json に id が T ではじまって数字以外を含む dennotation(たとえば T1.a.b)を入れると新規 ID が常に TNaN になります 8 | 4. Entity を何個作っても TNaN が振られます 9 | 5. 作成後 ID で DOM を選択する際に、最初の一個が選択されます 10 | 6. 4.1.14 で対応しました 11 | 7. 生成した ID を T 数字のみに制限しました 12 | 13 | ### -- 手段 -- 14 | 15 | 1. Term モードにする 16 | 2. Span を作る 17 | 3. Entity を追加する 18 | 4. 二つの作った Entity が選択されること 19 | 5. Span を作る 20 | 6. 後に作った Span の Entity だけが選択されること(前に作った Span の Entity が選択されないこと) 21 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220302_07.md: -------------------------------------------------------------------------------- 1 | ## URL が長いときはステータスバーに...を表示する 2 | 3 | ### 背景 4 | 5 | 1. URL が長い場合に、 `Source:` の後ろで改行され、URL がフッターの範囲外に出てしまい表示されていませんでした 6 | 2. 5.0.0 からステータスバーに表示する URL が長いときは省略して表示し、改行されないようにしました 7 | 3. ブラウザの幅が 726px 以下の時に、`Source:` の後ろで改行され、URL がフッターの範囲外に出てしまい表示されていませんでした 8 | 4. 6.4.30 で対応しまた 9 | 10 | ### -- 手段 -- 11 | 12 | 1. Editor0 を選択 13 | 2. ブラウザの幅を 726px 以下縮める 14 | 3. URL の末尾が切れて`...`が表示されること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220302_08.md: -------------------------------------------------------------------------------- 1 | ## ステータスバーの表示 2 | 3 | ### annotations ファイルを URL で読み込んだとき 4 | 5 | 1. 絶対 URL パスで読み込んだとき、ファイルの絶対パスが表示されること(editor0) 6 | 2. 絶対 URL パスで読み込んだとき、リンクが開けること(editor0) 7 | 3. 相対 URL パスで読み込んだとき、ファイルの絶対パスが表示されること(editor1) 8 | 4. 相対 URL パスで読み込んだとき、リンクが開けること(editor1) 9 | 10 | ### annotations ファイルをローカルファイルから読み込んだとき 11 | 12 | 1. annotations ファイルのファイル名と`(local file)`が表示されること 13 | 14 | ### annotations を inline で指定したとき 15 | 16 | 1. inline で annotations ファイルを読み込んだ場合は`inline`が表示されること(editor5) 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220304_01.md: -------------------------------------------------------------------------------- 1 | ## パスに日本語を含む URL から annotations ファイルを読み込んだときにステータスバーにデコードした URL を表示する 2 | 3 | ### 背景 4 | 5 | 1. 5.0.0 の開発中にステータスバーにパスが表示されない URL を発見しました。 6 | 2. パスに日本語を含む URL を URL エンコードしたままステータスバーに表示すると、URL が長くなりすぎます 7 | 3. Firefox では一定長で切られ、Chrome と Safari では改行されて、見えなくなります 8 | 4. 長過ぎる URL を省略して表示するで統一してもいいのですが、人間が見たいのはデコードした URL なので、ステータスバーに表示する 9 | URL をデコードします 10 | 11 | ### -- 手段 -- 12 | 13 | 1. `ゆりかごのうた.json` を読み込む 14 | 2. ステータスバーに表示される URL がデコードされていて、日本語になっていること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220304_02.md: -------------------------------------------------------------------------------- 1 | ## ラベルの定義に HTML タグが含まれているとき、パレットに HTML エスケープした文字列を Entity のラベルとして表示すること 2 | 3 | ### 背景 4 | 5 | 1. Entity のラベルには Type 定義の`label`を表示しています。 6 | 2. HTML エスケープしていないため、`label`に HTML タグを含む Type を定義すると、パレット上のラベルに任意の HTML タグを挿入することが可能です。 7 | 3. 6.4.26 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. Term モードにする 13 | 3. `q`を押してパレットを開く 14 | 4. `HTML tag label` のラベルが赤字の`Red color HTML label`ではなく、`Red color HTML label`であること 15 | 5. Block モードにする 16 | 6. `q`を押してパレットを開く 17 | 7. `HTML tag label` のラベルが赤字の`Red color HTML label`ではなく、`Red color HTML label`であること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220308_01.md: -------------------------------------------------------------------------------- 1 | ## ラベルの定義に HTML タグが含まれているとき、HTML エスケープした文字列を Entity のラベルとして表示すること 2 | 3 | ### 背景 4 | 5 | 1. Entity のラベルには Type 定義の`label`を表示しています。 6 | 2. HTML エスケープしていないため、`label`に HTML タグを含む Type を定義すると、Entity のラベルに任意の HTML タグを挿入することが可能です。 7 | 3. 6.4.25 で対応しました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor1 を選択 12 | 2. DenotationEntity `E31` のラベルが赤字の`Red color HTML label`ではなく、`Red color HTML label`であること 13 | 3. BlockEntity `B1` のラベルが赤字の`Red color HTML label`ではなく、`Red color HTML label`であること 14 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220308_03.md: -------------------------------------------------------------------------------- 1 | ## オートコンプリートの候補を表示したときに Relation 編集ダイアログに横スクロールバーが表示されないこと 2 | 3 | ### 背景 4 | 5 | 1. 6.4.20 で対応しました。 6 | 7 | ### --- 手段 --- 8 | 9 | 1. Editor1 を選択 10 | 2. Relation モードにする 11 | 3. Relation を選択する 12 | 4. `Change Label[W]`ボタンを押す 13 | 5. 既存の id を消す 14 | 6. `par`を入力 15 | 7. 候補に`parent@http://dbpedia.org/ontology/parent`が表示されること 16 | 8. ダイアログに横スクロールバー表示されないこと 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220309_02_keyboard.md: -------------------------------------------------------------------------------- 1 | ## 外部 JavaScript で URL パラメータから属性に設定した値が反映されること 2 | 3 | ### 背景 4 | 5 | 1. 4.5.0 で URL パラメータを読むのをやめました 6 | 2. 外部の JavaScript で textae-editor に設定した属性は読みます 7 | 3. 外部の JavaScript で textae-editor に URL パラメータの値を設定するサンプルの動作確認をします 8 | 9 | ### -- 手段 -- 10 | 11 | 1. を開く 12 | 2. 1_annotations が表示されること 13 | 3. Editor1 を選択 14 | 4. Edit モードであること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220309_03_monuse.md: -------------------------------------------------------------------------------- 1 | ## 2 つ以上連続した空白を選択してもエラーにならないこと 2 | 3 | ### 背景 4 | 5 | 1. 2 つ以上連続した空白を選択したときに、空白を一つだけ消して、残りの空白で Span を作成していました 6 | 2. Span のレンダリング時にエラーが起きていました 7 | 3. 6.1.44 で対応 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Editor9 を選択 12 | 2. Term モードにする 13 | 3. `stomach ache`の間の連続した空白を選択する 14 | 4. 選択が解除されて、何もおきないこと 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220310_01.md: -------------------------------------------------------------------------------- 1 | ## デフォルトの Type 定義の ID を変更したときにデフォルト情報も更新する 2 | 3 | ### 背景 4 | 5 | 1. デフォルトの Type 定義の ID を変更したとき、Type 定義の情報を更新します 6 | 2. デフォルトの ID 情報を更新していません。変更前の ID のままでした 7 | 3. デフォルトの Type 定義の ID を変更したとき、デフォルト情報が消えました 8 | 4. デフォルトの Type 定義の ID を変更したあとに、Entity をつくると変更前の ID で Entity が作成されます 9 | 5. 6.4.41 で対応しました 10 | 11 | ### --- 手段 --- 12 | 13 | 1. Editor0 を選択 14 | 2. Term モードにする 15 | 3. `Show label list editor [Q]`ボタンをクリックする 16 | 4. `Protein`の`Edit this type`ボタンをクリックする 17 | 5. `Id`を変更して、`OK`ボタンをクリックする 18 | 6. パレット上の`Proetin`のデフォルトマークが消えないこと 19 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220314_01.md: -------------------------------------------------------------------------------- 1 | ## Relation 編集ダイアログでラベルを持たない Relation を開く 2 | 3 | ### 背景 4 | 5 | 1. 6.3.29 で HTML 生成用のテンプレートを Handlebars.js からテンプレートリテラルに変えたときに、ラベルを持たない Entity のラベルに null と表示されるようになりました。 6 | 2. 6.4.44 で対応 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor0 を選択 11 | 2. Relation モードにする 12 | 3. Type の定義にラベルがない Relation を選択 13 | 4. `Change Label[W]`ボタンを押す 14 | 5. 編集ダイアログが開くこと 15 | 6. `Valnue/Lable`列の下の段に何も表示されないこと 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220315_03_keyboard.md: -------------------------------------------------------------------------------- 1 | ## Relation 編集ダイアログ 2 | 3 | ### W キー 4 | 5 | 1. Relation モードにする 6 | 2. Relation を選択する 7 | 3. `W`キーを押す 8 | 4. 編集ダイアログが開くこと 9 | 5. タイトルバーに選択した Relation の Type の id が表示されること 10 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220318_01.md: -------------------------------------------------------------------------------- 1 | ## BlockSpan 選択時のコントロールバーの見た目の変化 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. 6.2.51 で、`Add new entity[E]`, `Copy [C]`, `Cut [X]`が有効にならないようにしました 7 | 3. 6.2.52 で、`Replicate span annotation [R]`が有効にならないようにしました 8 | 9 | ### −− 手段 -- 10 | 11 | 1. Block モードにする 12 | 2. BlockSpan を選択する 13 | 3. コントロールバーの`Change label [W]`アイコンが有効になること 14 | 4. コントロールバーの`Delete [D]`アイコンが有効になること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220318_03.md: -------------------------------------------------------------------------------- 1 | ## Media Attribute 2 | 3 | ### 背景 4 | 5 | 1. String Attribute の値が画像の URL のときにラベルとして画像を表示します。 6 | 2. 画像の表示サイズは String Attribute の定義の Media Height で指定できます。デフォルトは他の Attribute と同じ高さです。 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. `E19`の Attribute として画像が表示されていること 12 | 3. `q`キーを押してパレットを開く 13 | 4. `free_text_predicate`タブを開く 14 | 5. `Edit this predicate.`ボタンをクリック 15 | 6. `Max Height`の値を数値で設定する 16 | 7. `OK`ボタンを押す 17 | 8. `E19`の Attribute の画像の高さが変わること 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220412_01.md: -------------------------------------------------------------------------------- 1 | ## BlockEntity 編集ダイアログの編集キャンセル 2 | 3 | ### 閉じるボタン 4 | 5 | 1. Block モードにする 6 | 2. BlockEntity を選択する 7 | 3. `W`キーを押す 8 | 4. 編集ダイアログが開くこと 9 | 5. 文字を変更する 10 | 6. `X`ボタンを押す 11 | 7. BlockEntity の id が変わらないこと 12 | 13 | ### Esc キー 14 | 15 | 1. Block モードにする 16 | 2. BlockEntity を選択する 17 | 3. `W`キーを押す 18 | 4. 編集ダイアログが開くこと 19 | 5. 文字を変更する 20 | 6. `Esc`キーを押す 21 | 7. BlockEntity の id が変わらないこと 22 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220412_02.md: -------------------------------------------------------------------------------- 1 | ## 編集モードを変更したらクリップボードを空にする 2 | 3 | ### 背景 4 | 5 | 1. 6.2.0 からブロック機能を追加 6 | 2. Term モードでコピーまたはカットした DenotationEntity を BlockSpan に貼り付けられるようになりました。 7 | 3. 6.4.68 で、編集モードを変更したときに、クリップボードを空にする対応をしました。 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Term モードにする 12 | 2. Entity を選択する 13 | 3. `x`キーを押してカットする 14 | 4. Block モードにする 15 | 5. カットされた Entity が半透明でなくなること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220413_01_mouse.md: -------------------------------------------------------------------------------- 1 | ## 親子 Span 編集 2 | 3 | ### 入れ子 Span を編集 4 | 5 | 1. 子の Span を親の範囲内でのばす 6 | 2. 親の Span を子にかぶらないように縮める 7 | 3. 戻す 8 | 9 | ### 同じサイズに 10 | 11 | 1. 親を子と同じサイズに縮める 12 | 2. 消える 13 | 14 | ### 親子 Span を入れ替える 15 | 16 | 1. 親 Span と子 Span の片側をあわせる 17 | 2. 親 Span の合っていない側を子 Span の内側に寄せる 18 | 3. 親と子の Type の位置が入れ替わること 19 | 20 | ### Type を2つ持つ Span に親を作る 21 | 22 | #### 背景 23 | 24 | 1. Grid の高さを子の Span の Type にかぶらないように上にずらしています 25 | 26 | #### -- 手段 -- 27 | 28 | 1. Type を二つ持つ Span に親を作る 29 | 2. 親の Type が二つの Type の上に表示されること 30 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220415_01.md: -------------------------------------------------------------------------------- 1 | ## 行の高さ調整ボタン 2 | 3 | ### 背景 4 | 5 | 1. 4.1.12 で行の高さ調整ボタンを追加しました 6 | 2. 4.1.16 の開発中にモジュール読み込み構文の修正漏れでエラーを起こしていました 7 | 3. 6.4.80 で、行の高さの計算に、BlockEntity の高さを含めることにしました 8 | 9 | ### -- 手段 -- 10 | 11 | 1. もっとも高い Grid を削除する 12 | 2. `Adjust LineHeight`ボタンをクリックする 13 | 3. 高さが調整されること 14 | 4. もっとも高い Grid より高い Grid を作る 15 | 5. `Adjust LineHeight`ボタンをクリックする 16 | 6. 高さが調整されること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220415_02.md: -------------------------------------------------------------------------------- 1 | ## Line Height を px で指定 2 | 3 | ### 背景 4 | 5 | 1. 4.1.12 で Line Height の単位を px に変えました 6 | 2. 4.1.11 までは`指定値 * 16px`を行の高さに設定していました 7 | 3. 4.2.1 で、LineHeight を変更しても Grid が移動しなくなっていました 8 | 9 | ### -- 手段 -- 10 | 11 | 1. Setting Dialog を開く 12 | 2. Line Height を増やす 13 | 3. 行の高さが px 単位で変更できること 14 | 4. 最大 500px まで選べること 15 | 5. 設定した値に応じて行の高さが変わること 16 | 6. 行の高さに合わせて Grid が移動すること 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220415_03.md: -------------------------------------------------------------------------------- 1 | ## Selection Attribute 定義の Value が唯一のときは、削除不可 2 | 3 | ### 背景 4 | 5 | 1. Selection Attribute の Value をすべて消そうとするとエラーが起きます 6 | 2. 6.1.57 で対応しました。 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. `Show label list editor [Q]`ボタンをクリックする 13 | 4. `selection`タブを選択 14 | 5. `default`の`Remove this value.`ボタンが無効なこと 15 | 6. `Add new value`ボタンをクリックする 16 | 7. `id`欄を入力する 17 | 8. `OK`ボタンを押す 18 | 9. `default`の`Remove this value.`ボタンが有効になること 19 | 10. 追加した Value の`Remove this value.`ボタンがクリックする 20 | 11. `default`の`Remove this value.`ボタンが無効になること 21 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220419_01.md: -------------------------------------------------------------------------------- 1 | ## Setting Dialog のタイトル 2 | 3 | ### 背景 4 | 5 | 1. タイトルを変更しました。 6 | 7 | ### -- 手段 -- 8 | 9 | 1. Setting Dialog を開く 10 | 2. Setting Dialog のタイトルが`Setting`であること 11 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220419_02.md: -------------------------------------------------------------------------------- 1 | ## URL からはテキストファイルのアノテーションは読み込めない 2 | 3 | ### 背景 4 | 5 | 1. 読み込み失敗時のメッセージが素っ気なかった 6 | 2. 4.1.12 から優しくなりました 7 | 3. 6.4.127 で不正なアノテーションを読み込んだ際に、不正なコンフィグレーションを読み込んだときのメッセージも表示されるようになりました 8 | 4. 6.4.142 で対応しました 9 | 5. 5.0.0 でローカルファイルからのテストファイル読み込み機能を追加しました。 10 | 11 | ### -- 手段 -- 12 | 13 | 1. アノテーション読込ダイアログを表示 14 | 2. URL 欄に`http://localhost:8000/dev/target.txt`を入力し、`Open`ボタンを押して、サーバーから読み込む 15 | 3. 右上に`http://localhost:8000/dev/target.txt is not a annotation file or its format is invalid.`と赤色のトースト表示がされること 16 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220503_01_firefox.md: -------------------------------------------------------------------------------- 1 | ## オートコンプリートの候補を表示したときに Entity 編集ダイアログに横スクロールバーが表示されないこと 2 | 3 | ### 背景 4 | 5 | 1. 5.0.6 で Entity ダイアログのオートコンプリートの候補の幅を、なるべく値が省略されないように、広くしました。 6 | 2. Firefox では、Entity ダイアログに横スクロールバーが表示されていました。5.2.7 で候補の幅を 5px 短くして、対応しました。 7 | 8 | ### --- 手段 --- 9 | 10 | 1. Editor1 を選択 11 | 2. Term モードにする 12 | 3. Attribute のない Entity を選択する 13 | 4. `Change Label[W]`ボタンを押す 14 | 5. 既存の id を消す 15 | 6. `par`を入力 16 | 7. 候補に`parent@http://dbpedia.org/ontology/parent`が表示されること 17 | 8. ダイアログに横スクロールバー表示されないこと 18 | -------------------------------------------------------------------------------- /userAcceptanceTest/20220503_02.md: -------------------------------------------------------------------------------- 1 | ## Setting Dialog の設定項目 2 | 3 | ### 背景 4 | 5 | 1. 4.1.16 で、instance/Simple モードの切り替えチェックボックスを消しました 6 | 2. 5.3.2 で、バージョン番号の表示を追加しました 7 | 8 | ### -- 手段 -- 9 | 10 | 1. Setting Dialog を開く 11 | 2. Type Gap があること 12 | 3. Line Height があること 13 | 4. Lock Edit Config があること 14 | 5. Version があること 15 | -------------------------------------------------------------------------------- /userAcceptanceTest/choice_test_devices.rb: -------------------------------------------------------------------------------- 1 | script = File.read(__FILE__).split("__END__\n").first 2 | value = DATA.gets 3 | 4 | puts value 5 | 6 | File.open(__FILE__, 'w') do 7 | _1.write script 8 | _1.write "__END__\n" 9 | _1.write DATA.read 10 | _1.write value 11 | end 12 | 13 | __END__ 14 | iPad 15 | Firefox 16 | Android 17 | -------------------------------------------------------------------------------- /userAcceptanceTest/userAcceptanceTest.md: -------------------------------------------------------------------------------- 1 | # 受け入れテスト 2 | 3 | 共通確認項目 4 | 5 | 1. `npm run dist`を実行します 6 | 2. `npm run dev:server`を実行します 7 | 3. を開きます 8 | 4. ブラウザの開発ツールを起動します。 9 | 5. 以下のテストを実行して、エラーが出ないこと 10 | --------------------------------------------------------------------------------