Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
77ea41de
Commit
77ea41de
authored
Feb 01, 2017
by
Sean Roberts
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adding client metric tracking for interactions with annotations
parent
3b5ba2df
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
108 additions
and
16 deletions
+108
-16
analytics.js
src/sidebar/analytics.js
+21
-2
annotation.js
src/sidebar/directive/annotation.js
+40
-6
annotation-test.js
src/sidebar/directive/test/annotation-test.js
+7
-0
analytics-test.js
src/sidebar/test/analytics-test.js
+29
-5
annotation-fixtures.js
src/sidebar/test/annotation-fixtures.js
+1
-1
app-controller-test.js
src/sidebar/test/app-controller-test.js
+7
-0
widget-controller-test.js
src/sidebar/test/widget-controller-test.js
+2
-1
widget-controller.js
src/sidebar/widget-controller.js
+1
-1
No files found.
src/sidebar/analytics.js
View file @
77ea41de
...
...
@@ -50,8 +50,27 @@ function analytics($analytics, $window, settings) {
* in our analytics. Example: 'sidebarOpened'. Use camelCase to track multiple
* words.
*/
track
:
function
(
event
){
$analytics
.
eventTrack
(
event
,
options
);
track
:
function
(
event
,
label
,
metricValue
){
$analytics
.
eventTrack
(
event
,
Object
.
assign
({},
{
label
:
label
||
undefined
,
metricValue
:
isNaN
(
metricValue
)
?
undefined
:
metricValue
,
},
options
));
},
events
:
{
ANNOTATION_CREATED
:
'annotationCreated'
,
ANNOTATION_DELETED
:
'annotationDeleted'
,
ANNOTATION_UPDATED
:
'annotationUpdated'
,
HIGHLIGHT_CREATED
:
'highlightCreated'
,
HIGHLIGHT_UPDATED
:
'highlightUpdated'
,
HIGHLIGHT_DELETED
:
'highlightDeleted'
,
PAGE_NOTE_CREATED
:
'pageNoteCreated'
,
PAGE_NOTE_UPDATED
:
'pageNoteUpdated'
,
PAGE_NOTE_DELETED
:
'pageNoteDeleted'
,
REPLY_CREATED
:
'replyCreated'
,
REPLY_UPDATED
:
'replyUpdated'
,
REPLY_DELETED
:
'replyDeleted'
,
SIDEBAR_OPENED
:
'sidebarOpened'
,
},
};
}
...
...
src/sidebar/directive/annotation.js
View file @
77ea41de
...
...
@@ -9,6 +9,7 @@ var persona = require('../filter/persona');
var
isNew
=
annotationMetadata
.
isNew
;
var
isReply
=
annotationMetadata
.
isReply
;
var
isPageNote
=
annotationMetadata
.
isPageNote
;
/** Return a human-readable error message for the given server error.
*
...
...
@@ -46,7 +47,7 @@ function updateModel(annotation, changes, permissions) {
// @ngInject
function
AnnotationController
(
$document
,
$q
,
$rootScope
,
$scope
,
$timeout
,
$window
,
annotationUI
,
$document
,
$q
,
$rootScope
,
$scope
,
$timeout
,
$window
,
an
alytics
,
an
notationUI
,
annotationMapper
,
drafts
,
flash
,
features
,
groups
,
permissions
,
serviceUrl
,
session
,
store
,
streamer
)
{
...
...
@@ -56,12 +57,18 @@ function AnnotationController(
/** Save an annotation to the server. */
function
save
(
annot
)
{
var
saved
;
if
(
annot
.
id
)
{
var
updating
=
!!
annot
.
id
;
if
(
updating
)
{
saved
=
store
.
annotation
.
update
({
id
:
annot
.
id
},
annot
);
}
else
{
saved
=
store
.
annotation
.
create
({},
annot
);
}
return
saved
.
then
(
function
(
savedAnnot
)
{
var
event
;
// Copy across internal properties which are not part of the annotation
// model saved on the server
savedAnnot
.
$tag
=
annot
.
$tag
;
...
...
@@ -70,6 +77,20 @@ function AnnotationController(
savedAnnot
[
k
]
=
annot
[
k
];
}
});
if
(
vm
.
isReply
()){
event
=
updating
?
analytics
.
events
.
REPLY_UPDATED
:
analytics
.
events
.
REPLY_CREATED
;
}
else
if
(
vm
.
isHighlight
()){
event
=
updating
?
analytics
.
events
.
HIGHLIGHT_UPDATED
:
analytics
.
events
.
HIGHLIGHT_CREATED
;
}
else
if
(
isPageNote
(
vm
.
annotation
))
{
event
=
updating
?
analytics
.
events
.
PAGE_NOTE_UPDATED
:
analytics
.
events
.
PAGE_NOTE_CREATED
;
}
else
{
event
=
updating
?
analytics
.
events
.
ANNOTATION_UPDATED
:
analytics
.
events
.
ANNOTATION_CREATED
;
}
analytics
.
track
(
event
);
return
savedAnnot
;
});
}
...
...
@@ -213,8 +234,22 @@ function AnnotationController(
errorMessage
(
reason
),
'Deleting annotation failed'
);
};
$scope
.
$apply
(
function
()
{
annotationMapper
.
deleteAnnotation
(
vm
.
annotation
).
then
(
null
,
onRejected
);
annotationMapper
.
deleteAnnotation
(
vm
.
annotation
).
then
(
function
(){
var
event
;
if
(
vm
.
isReply
()){
event
=
analytics
.
events
.
REPLY_DELETED
;
}
else
if
(
vm
.
isHighlight
()){
event
=
analytics
.
events
.
HIGHLIGHT_DELETED
;
}
else
if
(
isPageNote
(
vm
.
annotation
)){
event
=
analytics
.
events
.
PAGE_NOTE_DELETED
;
}
else
{
event
=
analytics
.
events
.
ANNOTATION_DELETED
;
}
analytics
.
track
(
event
);
},
onRejected
);
});
}
},
true
);
...
...
@@ -291,8 +326,7 @@ function AnnotationController(
// example there's no vm.annotation.highlight: true. Instead a highlight is
// defined as an annotation that isn't a page note or a reply and that
// has no text or tags.
var
isPageNote
=
(
vm
.
annotation
.
target
||
[]).
length
===
0
;
return
(
!
isPageNote
&&
!
isReply
(
vm
.
annotation
)
&&
!
vm
.
hasContent
());
return
(
!
isPageNote
(
vm
.
annotation
)
&&
!
isReply
(
vm
.
annotation
)
&&
!
vm
.
hasContent
());
}
};
...
...
src/sidebar/directive/test/annotation-test.js
View file @
77ea41de
...
...
@@ -82,6 +82,7 @@ describe('annotation', function() {
var
$scope
;
var
$timeout
;
var
$window
;
var
fakeAnalytics
;
var
fakeAnnotationMapper
;
var
fakeDrafts
;
var
fakeFlash
;
...
...
@@ -121,6 +122,11 @@ describe('annotation', function() {
beforeEach
(
angular
.
mock
.
module
(
function
(
$provide
)
{
sandbox
=
sinon
.
sandbox
.
create
();
fakeAnalytics
=
{
track
:
sandbox
.
stub
(),
events
:
{},
};
fakeAnnotationMapper
=
{
createAnnotation
:
sandbox
.
stub
().
returns
({
permissions
:
{
...
...
@@ -195,6 +201,7 @@ describe('annotation', function() {
hasPendingDeletion
:
sinon
.
stub
(),
};
$provide
.
value
(
'analytics'
,
fakeAnalytics
);
$provide
.
value
(
'annotationMapper'
,
fakeAnnotationMapper
);
$provide
.
value
(
'annotationUI'
,
fakeAnnotationUI
);
$provide
.
value
(
'drafts'
,
fakeDrafts
);
...
...
src/sidebar/test/analytics-test.js
View file @
77ea41de
...
...
@@ -2,6 +2,14 @@
var
analyticsService
=
require
(
'../analytics'
);
var
createEventObj
=
function
(
override
){
return
{
category
:
override
.
category
,
label
:
override
.
label
,
metricValue
:
override
.
metricValue
,
};
};
describe
(
'analytics'
,
function
()
{
var
$analyticsStub
;
...
...
@@ -32,31 +40,47 @@ describe('analytics', function () {
var
validTypes
=
[
'chrome-extension'
,
'embed'
,
'bookmarklet'
,
'via'
];
validTypes
.
forEach
(
function
(
appType
,
index
){
analyticsService
(
$analyticsStub
,
$windowStub
,
{
appType
:
appType
}).
track
(
'event'
+
index
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
index
],
[
'event'
+
index
,
{
category
:
appType
}
]);
assert
.
deepEqual
(
eventTrackStub
.
args
[
index
],
[
'event'
+
index
,
createEventObj
({
category
:
appType
})
]);
});
});
it
(
'sets category as embed if no other matches can be made'
,
function
()
{
analyticsService
(
$analyticsStub
,
$windowStub
).
track
(
'eventA'
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
{
category
:
'embed'
}
]);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
createEventObj
({
category
:
'embed'
})
]);
});
it
(
'sets category as via if url matches the via uri pattern'
,
function
()
{
$windowStub
.
document
.
referrer
=
'https://via.hypothes.is/'
;
analyticsService
(
$analyticsStub
,
$windowStub
).
track
(
'eventA'
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
{
category
:
'via'
}
]);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
createEventObj
({
category
:
'via'
})
]);
// match staging as well
$windowStub
.
document
.
referrer
=
'https://qa-via.hypothes.is/'
;
analyticsService
(
$analyticsStub
,
$windowStub
).
track
(
'eventB'
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
1
],
[
'eventB'
,
{
category
:
'via'
}
]);
assert
.
deepEqual
(
eventTrackStub
.
args
[
1
],
[
'eventB'
,
createEventObj
({
category
:
'via'
})
]);
});
it
(
'sets category as chrome-extension if protocol matches chrome-extension:'
,
function
()
{
$windowStub
.
location
.
protocol
=
'chrome-extension:'
;
analyticsService
(
$analyticsStub
,
$windowStub
).
track
(
'eventA'
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
{
category
:
'chrome-extension'
}
]);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
createEventObj
({
category
:
'chrome-extension'
})
]);
});
});
it
(
'allows custom labels to be sent for an event'
,
function
()
{
analyticsService
(
$analyticsStub
,
$windowStub
,
{
appType
:
'embed'
}).
track
(
'eventA'
,
'labelA'
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
createEventObj
({
category
:
'embed'
,
label
:
'labelA'
})]);
});
it
(
'allows custom metricValues to be sent for an event'
,
function
()
{
analyticsService
(
$analyticsStub
,
$windowStub
,
{
appType
:
'embed'
}).
track
(
'eventA'
,
null
,
242.2
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
createEventObj
({
category
:
'embed'
,
metricValue
:
242.2
})]);
});
it
(
'allows custom metricValues and labels to be sent for an event'
,
function
()
{
analyticsService
(
$analyticsStub
,
$windowStub
,
{
appType
:
'embed'
}).
track
(
'eventA'
,
'labelabc'
,
242.2
);
assert
.
deepEqual
(
eventTrackStub
.
args
[
0
],
[
'eventA'
,
createEventObj
({
category
:
'embed'
,
label
:
'labelabc'
,
metricValue
:
242.2
})]);
});
});
src/sidebar/test/annotation-fixtures.js
View file @
77ea41de
...
...
@@ -71,7 +71,7 @@ function oldAnnotation() {
return
{
id
:
'annotation_id'
,
$highlight
:
undefined
,
target
:
[
'foo'
,
'bar'
],
target
:
[
{
source
:
'source'
,
'selector'
:
[]
}
],
references
:
[],
text
:
'This is my annotation'
,
tags
:
[
'tag_1'
,
'tag_2'
],
...
...
src/sidebar/test/app-controller-test.js
View file @
77ea41de
...
...
@@ -12,6 +12,7 @@ describe('AppController', function () {
var
$rootScope
=
null
;
var
fakeAnnotationMetadata
=
null
;
var
fakeAnnotationUI
=
null
;
var
fakeAnalytics
=
null
;
var
fakeAuth
=
null
;
var
fakeDrafts
=
null
;
var
fakeFeatures
=
null
;
...
...
@@ -58,6 +59,11 @@ describe('AppController', function () {
clearSelectedAnnotations
:
sandbox
.
spy
(),
};
fakeAnalytics
=
{
track
:
sandbox
.
stub
(),
events
:
{},
};
fakeAuth
=
{};
fakeDrafts
=
{
...
...
@@ -107,6 +113,7 @@ describe('AppController', function () {
$provide
.
value
(
'annotationUI'
,
fakeAnnotationUI
);
$provide
.
value
(
'auth'
,
fakeAuth
);
$provide
.
value
(
'analytics'
,
fakeAnalytics
);
$provide
.
value
(
'drafts'
,
fakeDrafts
);
$provide
.
value
(
'features'
,
fakeFeatures
);
$provide
.
value
(
'frameSync'
,
fakeFrameSync
);
...
...
src/sidebar/test/widget-controller-test.js
View file @
77ea41de
...
...
@@ -71,7 +71,8 @@ describe('WidgetController', function () {
sandbox
=
sinon
.
sandbox
.
create
();
fakeAnalytics
=
{
track
:
sandbox
.
spy
(),
track
:
sandbox
.
stub
(),
events
:
{},
};
fakeAnnotationMapper
=
{
...
...
src/sidebar/widget-controller.js
View file @
77ea41de
...
...
@@ -202,7 +202,7 @@ module.exports = function WidgetController(
$scope
.
$on
(
'sidebarOpened'
,
function
()
{
analytics
.
track
(
'sidebarOpened'
);
analytics
.
track
(
analytics
.
events
.
SIDEBAR_OPENED
);
streamer
.
connect
();
});
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment