Commit 0cb4bf66 authored by csillag's avatar csillag

First implementation of Focus

Missing: search magic
parent 7bea1bd8
......@@ -202,7 +202,7 @@ $baseFontSize: 14px;
//HIGHLIGHTS////////////////////////////////
.annotator-highlights-always-on .annotator-hl,
.annotator-hl-active, .annotator-hl-temporary {
.annotator-hl-active, .annotator-hl-temporary, .annotator-hl-focused {
background: $highlightColor;
box-shadow:3px 3px 4px -1px #999999;
&::-moz-selection {
......@@ -223,7 +223,8 @@ $baseFontSize: 14px;
background: $highlightModeColor;
}
.annotator-highlights-always-on .annotator-hl-active, {
.annotator-highlights-always-on .annotator-hl-active,
.annotator-highlights-always-on .annotator-hl-focused {
box-shadow:3px 3px 4px 3px #999999;
}
......
......@@ -564,13 +564,16 @@ class Annotation
switch $scope.action
when 'create'
switch
when annotator.isComment(annotation) and
$rootScope.viewState.view isnt "Comments"
$rootScope.applyView "Comments"
when not annotator.isReply(annotation) and
$rootScope.viewState.view not in ["Document", "Selection"]
$rootScope.applyView "Screen"
# First, focus on the newly created annotation
unless annotator.isReply annotation
$rootScope.focus annotation, true
if annotator.isComment(annotation) and
$rootScope.viewState.view isnt "Comments"
$rootScope.applyView "Comments"
else if not annotator.isReply(annotation) and
$rootScope.viewState.view not in ["Document", "Selection"]
$rootScope.applyView "Screen"
annotator.publish 'annotationCreated', annotation
when 'delete'
root = $scope.$root.annotations
......@@ -761,7 +764,7 @@ class Viewer
) ->
{providers, threading} = annotator
$scope.focus = (annotation) ->
$scope.activate = (annotation) ->
if angular.isArray annotation
highlights = (a.$$tag for a in annotation when a?)
else if angular.isObject annotation
......@@ -832,7 +835,7 @@ class Search
result = true
result
$scope.focus = (annotation) ->
$scope.activate = (annotation) ->
if angular.isArray annotation
highlights = (a.$$tag for a in annotation when a?)
else if angular.isObject annotation
......@@ -848,6 +851,7 @@ class Search
# Temporary workaround, until search result annotation card
# scopes get their 'annotation' fields, too.
return unless annotation
for p in providers
p.channel.notify
method: 'scrollTo'
......
......@@ -213,7 +213,7 @@ tabReveal = ['$parse', ($parse) ->
]
thread = ['$window', ($window) ->
thread = ['$rootScope', '$window', ($rootScope, $window) ->
# Helper -- true if selection ends inside the target and is non-empty
ignoreClick = (event) ->
sel = $window.getSelection()
......@@ -225,11 +225,25 @@ thread = ['$window', ($window) ->
link: (scope, elem, attr, ctrl) ->
childrenEditing = {}
# If this is supposed to be focused, then open it
if scope.annotation in $rootScope.focused
scope.collapsed = false
scope.$on "focusChange", ->
if scope.annotation in $rootScope.focused
scope.collapsed = false
else
scope.collapsed = true
scope.toggleCollapsed = (event) ->
event.stopPropagation()
return if (ignoreClick event) or Object.keys(childrenEditing).length
scope.collapsed = !scope.collapsed
scope.openDetails scope.annotation unless scope.collapsed
if scope.collapsed
$rootScope.unFocus scope.annotation, true
else
scope.openDetails scope.annotation
$rootScope.focus scope.annotation, true
scope.$on 'toggleEditing', (event) ->
{$id, editing} = event.targetScope
......
......@@ -33,6 +33,9 @@ class Annotator.Guest extends Annotator
# Create an array for holding the comments
@comments = []
# These are in focus (visually marked here, and open in sidebar)
@focusedAnnotations = []
@frame = $('<div></div>')
.appendTo(@wrapper)
.addClass('annotator-frame annotator-outer annotator-collapsed')
......@@ -111,6 +114,18 @@ class Annotator.Guest extends Annotator
this.publish "finalizeHighlights"
)
.bind('setFocusedHighlights', (ctx, tags=[]) =>
this.focusedAnnotations = []
for hl in @getHighlights()
annotation = hl.annotation
if annotation.$$tag in tags
this.focusedAnnotations.push annotation
hl.setFocused true, true
else
hl.setFocused false, true
this.publish "finalizeHighlights"
)
.bind('scrollTo', (ctx, tag) =>
for hl in @getHighlights()
if hl.annotation.$$tag is tag
......@@ -188,24 +203,28 @@ class Annotator.Guest extends Annotator
_setupViewer: -> this
_setupEditor: -> this
showViewer: (viewName, annotations) =>
showViewer: (viewName, annotations, focused = false) =>
@panel?.notify
method: "showViewer"
params:
view: viewName
ids: (a.id for a in annotations)
focused: focused
toggleViewerSelection: (annotations) =>
toggleViewerSelection: (annotations, focused = false) =>
@panel?.notify
method: "toggleViewerSelection"
params: (a.id for a in annotations)
params:
ids: (a.id for a in annotations)
focused: focused
updateViewer: (viewName, annotations) =>
updateViewer: (viewName, annotations, focused = false) =>
@panel?.notify
method: "updateViewer"
params:
view: viewName
ids: (a.id for a in annotations)
focused: focused
showEditor: (annotation) => @plugins.Bridge.showEditor annotation
......@@ -271,36 +290,54 @@ class Annotator.Guest extends Annotator
else
super
onAnchorMouseover: (event) ->
# Get the list of annotations impacted by a mouse event
_getImpactedAnnotations: (event) ->
# Get the raw list
annotations = event.data.getAnnotations event
# Are the highlights supposed to be visible?
if (@tool is 'highlight') or @visibleHighlights
this.addEmphasis event.data.getAnnotations event
# Just use the whole list
annotations
else
# We need to check for focused annotations
a for a in annotations when a in this.focusedAnnotations
onAnchorMouseover: (event) ->
this.addEmphasis this._getImpactedAnnotations event
onAnchorMouseout: (event) ->
if (@tool is 'highlight') or @visibleHighlights
this.removeEmphasis event.data.getAnnotations event
this.removeEmphasis this._getImpactedAnnotations event
# When clicking on a highlight in highlighting mode,
# set @noBack to true to prevent the sidebar from closing
onAnchorMousedown: (event) =>
if (@tool is 'highlight') or @visibleHighlights
if this._getImpactedAnnotations(event).length
@noBack = true
# When clicking on a highlight in highlighting mode,
# tell the sidebar to bring up the viewer for the relevant annotations
onAnchorClick: (event) =>
return unless (@tool is 'highlight') or @visibleHighlights and @noBack
# Select some annotations.
#
# toggle: should this toggle membership in an existing selection?
# focus: should these annotation become focused?
selectAnnotations: (annotations, toggle, focus) =>
# Switch off dynamic mode; we are going to "Selection" scope
@plugins.Heatmap.dynamicBucket = false
annotations = event.data.getAnnotations event
if event.metaKey or event.ctrlKey
if toggle
# Tell sidebar to add these annotations to the sidebar
this.toggleViewerSelection annotations
this.toggleViewerSelection annotations, focus
else
# Tell sidebar to show the viewer for these annotations
this.showViewer "Selection", annotations
this.showViewer "Selection", annotations, focus
# When clicking on a highlight in highlighting mode,
# tell the sidebar to bring up the viewer for the relevant annotations
onAnchorClick: (event) =>
annotations = this._getImpactedAnnotations event
return unless annotations.length and @noBack
this.selectAnnotations annotations,
(event.metaKey or event.ctrlKey), true
# We have already prevented closing the sidebar, now reset this flag
@noBack = false
......
......@@ -470,11 +470,8 @@ class Annotator.Plugin.Heatmap extends Annotator.Plugin
@commentClick()
else
d3.event.stopPropagation()
@dynamicBucket = false
if d3.event.ctrlKey or d3.event.metaKey
annotator.toggleViewerSelection @buckets[bucket]
else
annotator.showViewer "Selection", @buckets[bucket]
annotator.selectAnnotations @buckets[bucket].slice(),
(d3.event.ctrlKey or d3.event.metaKey), true
tabs.exit().remove()
......
......@@ -173,6 +173,25 @@ class Hypothesis extends Annotator
# Track the visible annotations in the root scope
$rootScope.annotations = []
$rootScope.search_annotations = []
$rootScope.focused = []
$rootScope.focus = (annotation, announce = false) =>
unless annotation
console.log "Warning: trying to focus on null annotation"
return
return if annotation in $rootScope.focused
$rootScope.focused.push annotation
this._broadcastFocusInfo() if announce
$rootScope.unFocus = (annotation, announce = false) =>
index = $rootScope.focused.indexOf annotation
return if index is -1
$rootScope.focused.splice index, 1
this._broadcastFocusInfo() if announce
# Add new annotations to the view when they are created
this.subscribe 'annotationCreated', (a) =>
......@@ -184,6 +203,13 @@ class Hypothesis extends Annotator
$rootScope.annotations = $rootScope.annotations.filter (b) -> b isnt a
$rootScope.search_annotations = $rootScope.search_annotations.filter (b) -> b.message?
_broadcastFocusInfo: ->
$rootScope = @element.injector().get '$rootScope'
for p in @providers
p.channel.notify
method: 'setFocusedHighlights'
params: (a.$$tag for a in $rootScope.focused)
_setupXDM: (options) ->
$rootScope = @element.injector().get '$rootScope'
......@@ -216,22 +242,22 @@ class Hypothesis extends Annotator
$rootScope.$apply => this.show()
)
.bind('showViewer', (ctx, {view, ids}) =>
.bind('showViewer', (ctx, {view, ids, focused}) =>
ids ?= []
return unless this.discardDrafts()
$rootScope.$apply =>
this.showViewer view, this._getAnnotationsFromIDs ids
this.showViewer view, this._getAnnotationsFromIDs(ids), focused
)
.bind('updateViewer', (ctx, {view, ids}) =>
.bind('updateViewer', (ctx, {view, ids, focused}) =>
ids ?= []
$rootScope.$apply =>
this.updateViewer view, this._getAnnotationsFromIDs ids
this.updateViewer view, this._getAnnotationsFromIDs(ids), focused
)
.bind('toggleViewerSelection', (ctx, ids=[]) =>
.bind('toggleViewerSelection', (ctx, {ids, focused}) =>
$rootScope.$apply =>
this.toggleViewerSelection this._getAnnotationsFromIDs ids
this.toggleViewerSelection this._getAnnotationsFromIDs(ids), focused
)
.bind('setTool', (ctx, name) =>
......@@ -322,12 +348,12 @@ class Hypothesis extends Annotator
annotation.reply_list = children.sort(@sortAnnotations).reverse()
@buildReplyList children
toggleViewerSelection: (annotations=[]) =>
toggleViewerSelection: (annotations=[], focused) =>
annotations = annotations.filter (a) -> a?
@element.injector().invoke [
'$rootScope',
($rootScope) =>
if $rootScope.view is "Selection"
if $rootScope.viewState.view is "Selection"
# We are already in selection mode; just XOR this list
# to the current selection
@buildReplyList annotations
......@@ -336,36 +362,61 @@ class Hypothesis extends Annotator
index = list.indexOf a
if index isnt -1
list.splice index, 1
$rootScope.unFocus a, true
else
list.push a
if focused
$rootScope.focus a, true
else
# We are not in selection mode,
# so we switch to it, and make this list
# the new selection
$rootScope.view = "Selection"
$rootScope.viewState.view = "Selection"
$rootScope.annotations = annotations
]
this
updateViewer: (viewName, annotations=[]) =>
updateViewer: (viewName, annotations=[], focused = false) =>
annotations = annotations.filter (a) -> a?
@element.injector().invoke [
'$rootScope',
($rootScope) =>
@buildReplyList annotations
# Do we have to replace the focused list with this?
if focused
# Nuke the old focus list
$rootScope.focused = []
# Add the new elements
for a in annotations
$rootScope.focus a, true
else
# Go over the old list, and unfocus the ones
# that are not on this list
for a in $rootScope.focused.slice() when a not in annotations
$rootScope.unFocus a, true
# Update the main annotations list
$rootScope.annotations = annotations
$rootScope.applyView viewName
# Announce focus changes
$rootScope.$broadcast 'focusChange'
unless $rootScope.viewState.view is viewName
# We are changing the view
$rootScope.viewState.view = viewName
$rootScope.showViewSort true, true
]
this
showViewer: (viewName, annotations=[]) =>
showViewer: (viewName, annotations=[], focused = false) =>
this.show()
@element.injector().invoke [
'$location',
($location) =>
$location.path('/viewer').replace()
]
this.updateViewer viewName, annotations
this.updateViewer viewName, annotations, focused
addEmphasis: (annotations=[]) =>
annotations = annotations.filter (a) -> a? # Filter out null annotations
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment