diff --git a/app/assets/images/checkmark.png b/app/assets/images/checkmark.png new file mode 100644 index 000000000..feaa040d5 Binary files /dev/null and b/app/assets/images/checkmark.png differ diff --git a/app/assets/javascripts/components/app.cjsx b/app/assets/javascripts/components/app.cjsx index 7cb62d106..3785143b0 100644 --- a/app/assets/javascripts/components/app.cjsx +++ b/app/assets/javascripts/components/app.cjsx @@ -40,7 +40,7 @@ App = React.createClass error: "Having trouble logging you in" setTutorialComplete: -> - previously_saved = @state.user?.tutorial_complete? + previously_saved = @state.user?.tutorial_complete # Immediately ammend user object with tutorial_complete flag so that we can hide the Tutorial: @setState user: $.extend(@state.user ? {}, tutorial_complete: true) diff --git a/app/assets/javascripts/components/mark/tools/rectangle-tool/index.cjsx b/app/assets/javascripts/components/mark/tools/rectangle-tool/index.cjsx index ce2b07764..167bad719 100644 --- a/app/assets/javascripts/components/mark/tools/rectangle-tool/index.cjsx +++ b/app/assets/javascripts/components/mark/tools/rectangle-tool/index.cjsx @@ -200,7 +200,7 @@ module.exports = React.createClass classes.push 'transcribable' if @props.isTranscribable classes.push 'interim' if @props.interim classes.push if @props.disabled then 'committed' else 'uncommitted' - classes.push "tanscribing" if @checkLocation() + classes.push "tanscribing" if @inTranscribeWorkflow() x1 = @props.mark.x width = @props.mark.width diff --git a/app/assets/javascripts/components/subject-viewer.cjsx b/app/assets/javascripts/components/subject-viewer.cjsx index 977a72a83..07a335e12 100644 --- a/app/assets/javascripts/components/subject-viewer.cjsx +++ b/app/assets/javascripts/components/subject-viewer.cjsx @@ -54,6 +54,16 @@ module.exports = React.createClass @loadImage @props.subject.location.standard window.addEventListener "resize", this.updateDimensions + $(document).keydown (e) => + # Handle keypress + if e.keyCode == 46 + mark = @state.selectedMark + @destroyMark mark if mark? + + # Handle keypress + else if e.keyCode == 13 + @submitMark(@state.uncommittedMark) if @state.uncommittedMark? + scrollToSubject: -> # scroll to mark when transcribing if @props.workflow.name is 'transcribe' @@ -108,10 +118,10 @@ module.exports = React.createClass # VARIOUS EVENT HANDLERS # Commit mark - submitMark: (mark) -> + submitMark: (mark, oncomplete) -> return unless mark? @props.onComplete? mark - @setUncommittedMark null # reset uncommitted mark + @setUncommittedMark null, oncomplete # reset uncommitted mark # Handle initial mousedown: handleInitStart: (e) -> @@ -198,10 +208,11 @@ module.exports = React.createClass mark.belongsToUser = true @setUncommittedMark mark - setUncommittedMark: (mark) -> + setUncommittedMark: (mark, oncomplete) -> @setState uncommittedMark: mark, - selectedMark: mark #, => @forceUpdate() # not sure if this is needed? + selectedMark: mark, () => + oncomplete() if oncomplete? setView: (viewX, viewY, viewWidth, viewHeight) -> @setState {viewX, viewY, viewWidth, viewHeight} @@ -235,7 +246,7 @@ module.exports = React.createClass # First, if we're blurring some other uncommitted mark, commit it: if @state.uncommittedMark? && mark != @state.uncommittedMark - @submitMark sel + @submitMark @state.uncommittedMark, sel else sel() diff --git a/app/assets/javascripts/components/transcribe/index.cjsx b/app/assets/javascripts/components/transcribe/index.cjsx index 3326ec09a..1be14a66d 100644 --- a/app/assets/javascripts/components/transcribe/index.cjsx +++ b/app/assets/javascripts/components/transcribe/index.cjsx @@ -101,7 +101,9 @@ module.exports = React.createClass # rename to Classifier page: @props.query.page render: -> - if @props.params.workflow_id? and @props.params.parent_subject_id? + if @props.query.from == 'verify' + transcribeMode = 'verify' + else if @props.params.workflow_id? and @props.params.parent_subject_id? transcribeMode = 'page' else if @props.params.subject_id transcribeMode = 'single' @@ -113,6 +115,7 @@ module.exports = React.createClass # rename to Classifier else isLastSubject = null currentAnnotation = @getCurrentClassification().annotation + currentAnnotation = @props.query.annotation if @props.query.annotation? TranscribeComponent = @getCurrentTool() # @state.currentTool onFirstAnnotation = currentAnnotation?.task is @getActiveWorkflow().first_task diff --git a/app/assets/javascripts/components/transcribe/tools/composite-tool/index.cjsx b/app/assets/javascripts/components/transcribe/tools/composite-tool/index.cjsx index 238b80935..2bb2a656e 100644 --- a/app/assets/javascripts/components/transcribe/tools/composite-tool/index.cjsx +++ b/app/assets/javascripts/components/transcribe/tools/composite-tool/index.cjsx @@ -55,7 +55,7 @@ CompositeTool = React.createClass # If there are more inputs, move focus to next input # Otherwise commit annotation (which is default behavior when there's only one input handleCompletedField: -> - field_keys = (c.value for c of @props.task.tool_config.options) + field_keys = (c.value for c in @props.task.tool_config.options) next_field_key = field_keys[ field_keys.indexOf(@state.active_field_key) + 1 ] if next_field_key? @@ -63,7 +63,9 @@ CompositeTool = React.createClass , => @forceUpdate() else - @commitAnnotation() + # Default to first field key (in case we're repeating this task) + @setState active_field_key: field_keys[0], () => + @commitAnnotation() # User moved focus to an input: handleFieldFocus: (annotation_key) -> @@ -79,6 +81,8 @@ CompositeTool = React.createClass if @props.transcribeMode is 'page' or @props.transcribeMode is 'single' if @props.isLastSubject and not @props.task.next_task? @props.returnToMarking() + else if @props.transcribeMode == 'verify' + @transitionTo 'verify' # this can go into a mixin? (common across all transcribe tools) returnToMarking: -> @@ -109,6 +113,8 @@ CompositeTool = React.createClass else if @props.isLastSubject and ( @props.transcribeMode is 'page' or @props.transcribeMode is 'single' ) 'Return to Marking' + else if @props.transcribeMode is 'verify' + 'Return to Verify' else 'Next Entry' buttons.push diff --git a/app/assets/javascripts/components/transcribe/tools/text-tool/index.cjsx b/app/assets/javascripts/components/transcribe/tools/text-tool/index.cjsx index 5dbb2c424..a395ac8af 100644 --- a/app/assets/javascripts/components/transcribe/tools/text-tool/index.cjsx +++ b/app/assets/javascripts/components/transcribe/tools/text-tool/index.cjsx @@ -1,4 +1,5 @@ React = require 'react' +{Navigation} = require 'react-router' DraggableModal = require 'components/draggable-modal' SmallButton = require 'components/buttons/small-button' HelpButton = require 'components/buttons/help-button' @@ -7,6 +8,7 @@ IllegibleSubjectButton = require 'components/buttons/illegible-subject-button' TextTool = React.createClass displayName: 'TextTool' + mixins: [Navigation] # load subjects and set state variables: subjects, classification getInitialState: -> annotation: @props.annotation ? {} @@ -119,6 +121,8 @@ TextTool = React.createClass if @props.transcribeMode is 'page' or @props.transcribeMode is 'single' if @props.isLastSubject and not @props.task.next_task? @props.returnToMarking() + else if @props.transcribeMode == 'verify' + @transitionTo 'verify' # Get key to use in annotations hash (i.e. typically 'value', unless included in composite tool) fieldKey: -> @@ -235,6 +239,8 @@ TextTool = React.createClass else if @props.isLastSubject and ( @props.transcribeMode is 'page' or @props.transcribeMode is 'single' ) 'Return to Marking' + else if @props.transcribeMode is 'verify' + 'Return to Verify' else 'Next Entry' buttons.push diff --git a/app/assets/javascripts/components/verify/tools/verify-tool/index.cjsx b/app/assets/javascripts/components/verify/tools/verify-tool/index.cjsx index 76235bce0..c2fa4d45f 100644 --- a/app/assets/javascripts/components/verify/tools/verify-tool/index.cjsx +++ b/app/assets/javascripts/components/verify/tools/verify-tool/index.cjsx @@ -64,6 +64,11 @@ VerifyTool = React.createClass y = data.y + yPad return {x,y} + editAnnotation: (ann) -> + url = "/#/transcribe/#{@props.subject.parent_subject_id}?scrollX=#{window.scrollX}&scrollY=#{window.scrollY}&from=verify" + url += "&" + ("annotation[#{k}]=#{v}" for k,v of ann).join('&') + window.location.href = url + render: -> # return null unless @props.viewerSize? && @props.subject? # return null if ! @props.scale? || ! @props.scale.horizontal? @@ -115,10 +120,13 @@ VerifyTool = React.createClass # TODO: hack to approximate a friendly label in emigrant; should pull from original label: label = label.replace(/em_/,'') label = label.replace(/_/g, ' ') -
  • {label} {v}
  • +
  • {label} {v}
  • } + { if @props.workflow.subjects_editable + + } } diff --git a/app/assets/javascripts/lib/mark-button-mixin.cjsx b/app/assets/javascripts/lib/mark-button-mixin.cjsx index b9160d684..e9e7ab786 100644 --- a/app/assets/javascripts/lib/mark-button-mixin.cjsx +++ b/app/assets/javascripts/lib/mark-button-mixin.cjsx @@ -28,12 +28,12 @@ module.exports = markStatus: markStatus locked: '' - checkLocation: ()-> + inTranscribeWorkflow: ()-> pattern = new RegExp('^(#\/transcribe)') pattern.test("#{window.location.hash}") renderMarkButton: -> - return null if @checkLocation() + return null if @inTranscribeWorkflow() 0 && (opt = options[0])? && opt.next_task? + if (options = (c for c in task.tool_config?.options when c.value is @getCurrentClassification()?.annotation?.value)) && options.length > 0 && (opt = options[0])? && opt.next_task? nextKey = opt.next_task else nextKey = @getTasks()[@state.taskKey].next_task diff --git a/app/assets/stylesheets/verify-tool.styl b/app/assets/stylesheets/verify-tool.styl index 488694b03..c96acbae0 100644 --- a/app/assets/stylesheets/verify-tool.styl +++ b/app/assets/stylesheets/verify-tool.styl @@ -4,31 +4,62 @@ label margin 1em - ul + & > ul padding-left 0 list-style none text-align left - li + & > li + + position relative + flexbox(flex) + flex-direction(row) + flex-wrap(nowrap) + padding-bottom 1em + + button.edit-button + z-index 2 + opacity 0.6 + padding 0.2em 0.6em + margin-left 10px + + flex(shrink: 0) + + &:hover + opacity 1 + a color black text-decoration none + // display block + flex(grow: 1, shrink: 1) + background-color white + border-radius 6px + + opacity 0.7 ul.choice - margin 1em 0 + z-index 1 + // margin 1em 0 padding 0.5em - - background-color white - border-radius 6px - - opacity 0.7 + list-style none span font-weight bold + &.value + font-family "courier new", "courier", monospace + &.label padding-right 10px font-weight normal - &:hover - opacity 1 + &:hover + opacity 1 + box-shadow 0 0 3px 3px rgba(0,0,0,.1) + + ul + background-image url(/assets/checkmark.png) + background-repeat no-repeat + background-position 96% center + diff --git a/app/models/workflow.rb b/app/models/workflow.rb index 7a380337a..0193fe1c3 100644 --- a/app/models/workflow.rb +++ b/app/models/workflow.rb @@ -19,6 +19,9 @@ class Workflow # this `false` to prevent a user's transcriptions from being verified by same # user: field :subjects_classifiable_by_creator, type: Boolean, default: true + # Controls whether the user-generated subject shown may be "edited" (cloned, really) + # Currently only implemented as an EDIT button in Verify (user can transcribe using a prev transcription as a basis) + field :subjects_editable, type: Boolean, default: true field :active_subjects, type: Integer, default: 0 field :order, type: Integer, default: 0 diff --git a/app/serializers/workflow_serializer.rb b/app/serializers/workflow_serializer.rb index 6627c38f3..dd842a0f3 100644 --- a/app/serializers/workflow_serializer.rb +++ b/app/serializers/workflow_serializer.rb @@ -1,5 +1,5 @@ class WorkflowSerializer < ActiveModel::MongoidSerializer - attributes :id, :name, :label, :tasks, :retire_limit, :subject_fetch_limit, :first_task, :active_subjects, :generates_subjects_for, :order + attributes :id, :name, :label, :tasks, :retire_limit, :subject_fetch_limit, :first_task, :active_subjects, :generates_subjects_for, :order, :subjects_editable def id object._id.to_s diff --git a/project/emigrant/workflows/verify.json b/project/emigrant/workflows/verify.json index 95dd6df05..04b58c446 100644 --- a/project/emigrant/workflows/verify.json +++ b/project/emigrant/workflows/verify.json @@ -8,6 +8,7 @@ "generates_subjects_max": 20, "generates_subjects_agreement": 0.75, "subjects_classifiable_by_creator": false, + "subjects_editable": true, "tasks": {