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
58d19bf0
Commit
58d19bf0
authored
Dec 04, 2015
by
Robert Knight
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2762 from hypothesis/2728-refactor-highlight-saving
Refactor saving highlights in AnnotationController
parents
696909f7
6b10b936
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
479 additions
and
161 deletions
+479
-161
annotation.js
h/static/scripts/directive/annotation.js
+84
-33
annotation-test.js
h/static/scripts/directive/test/annotation-test.js
+395
-128
No files found.
h/static/scripts/directive/annotation.js
View file @
58d19bf0
...
...
@@ -186,7 +186,81 @@ function AnnotationController(
// Set the permissions of new annotations.
model
.
permissions
=
model
.
permissions
||
permissions
[
'default'
](
model
.
group
);
var
highlight
=
model
.
$highlight
;
/**
* `true` if this AnnotationController instance was created as a result of
* the highlight button being clicked.
*
* `false` if the annotation button was clicked, or if this is a highlight or
* annotation that was fetched from the server (as opposed to created new
* client-side).
*/
var
newlyCreatedByHighlightButton
=
model
.
$highlight
||
false
;
/**
* @ngdoc method
* @name annotation.AnnotationController#isHighlight.
* @returns {boolean} true if the annotation is a highlight, false otherwise
*/
vm
.
isHighlight
=
function
()
{
if
(
newlyCreatedByHighlightButton
)
{
return
true
;
}
else
if
(
!
model
.
id
)
{
// If an annotation has no model.id (i.e. it has not been saved to the
// server yet) and newlyCreatedByHighlightButton is false, then it must
// be an annotation not a highlight (even though it may not have any
// text or tags yet).
return
false
;
}
else
{
// Once an annotation has been saved to the server there's no longer a
// simple property that says whether it's a highlight or not. For
// example there's no model.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
=
(
model
.
target
||
[]).
length
===
0
;
var
isReply
=
(
model
.
references
||
[]).
length
!==
0
;
return
(
!
isPageNote
&&
!
isReply
&&
!
vm
.
hasContent
());
}
};
/** Save this annotation if it's a new highlight.
*
* The highlight will be saved to the server if the user is logged in,
* saved to drafts if they aren't.
*
* If the annotation is not new (it has already been saved to the server) or
* is not a highlight then nothing will happen.
*
*/
function
saveNewHighlight
()
{
if
(
model
.
id
)
{
// Already saved.
return
;
}
if
(
!
vm
.
isHighlight
())
{
// Not a highlight,
return
;
}
if
(
model
.
user
)
{
// User is logged in, save to server.
// Highlights are always private.
model
.
permissions
=
permissions
.
private
();
model
.
$create
().
then
(
function
()
{
$rootScope
.
$emit
(
'annotationCreated'
,
model
);
});
}
else
{
// User isn't logged in, save to drafts.
updateDraft
(
model
);
}
}
// Automatically save new highlights to the server when they're created.
// Note that this line also gets called when the user logs in (since
// AnnotationController instances are re-created on login) so serves to
// automatically save highlights that were created while logged out when you
// log in.
saveNewHighlight
();
/**
* @ngdoc method
...
...
@@ -229,18 +303,6 @@ function AnnotationController(
return
$q
.
when
(
tags
.
filter
(
query
));
};
/**
* @ngdoc method
* @name annotation.AnnotationController#isHighlight.
* @returns {boolean} True if the annotation is a highlight.
*/
vm
.
isHighlight
=
function
()
{
var
targetLength
=
(
model
.
target
||
[]).
length
;
var
referencesLength
=
(
model
.
references
||
[]).
length
;
var
tagsLength
=
(
model
.
tags
||
[]).
length
;
return
(
targetLength
&&
!
referencesLength
&&
!
(
model
.
text
||
tagsLength
));
};
/**
* @ngdoc method
* @name annotation.AnnotationController#isPrivate
...
...
@@ -302,8 +364,8 @@ function AnnotationController(
/**
* @ngdoc method
* @name annotation.AnnotaitonController#hasContent
* @returns {boolean}
True if the currently edited annotation has
*
content (ie. is not just a highlight)
* @returns {boolean}
`true` if this annotation has content, `false`
*
otherwise.
*/
vm
.
hasContent
=
function
()
{
var
textLength
=
(
vm
.
annotation
.
text
||
''
).
length
;
...
...
@@ -573,19 +635,6 @@ function AnnotationController(
drafts
.
remove
(
model
);
}
// Save highlights once logged in.
if
(
vm
.
isHighlight
()
&&
highlight
)
{
if
(
model
.
user
&&
!
model
.
id
)
{
model
.
permissions
=
permissions
.
private
();
model
.
$create
().
then
(
function
()
{
$rootScope
.
$emit
(
'annotationCreated'
,
model
);
});
highlight
=
false
;
// Prevents double highlight creation.
}
else
{
updateDraft
(
model
);
}
}
updateTimestamp
(
model
===
old
);
// Repeat on first run.
vm
.
render
();
},
true
);
...
...
@@ -604,12 +653,14 @@ function AnnotationController(
}
});
// If this is a new annotation or we have unsaved changes,
// then start editing immediately.
var
isNewAnnotation
=
!
(
model
.
id
||
(
vm
.
isHighlight
()
&&
highlight
));
if
(
isNewAnnotation
||
drafts
.
get
(
model
))
{
// If this annotation is not a highlight and if it's new (has just been
// created by the annotate button) or it has edits not yet saved to the
// server - then open the editor on AnnotationController instantiation.
if
(
!
newlyCreatedByHighlightButton
)
{
if
(
!
model
.
id
||
drafts
.
get
(
model
))
{
vm
.
edit
();
}
}
// When the current group changes, persist any unsaved changes using
// the drafts service. They will be restored when this annotation is
...
...
h/static/scripts/directive/test/annotation-test.js
View file @
58d19bf0
...
...
@@ -303,7 +303,6 @@ describe('annotation.js', function() {
var
$scope
;
var
$timeout
;
var
$window
;
var
annotation
;
var
fakeAnnotationMapper
;
var
fakeAnnotationUI
;
var
fakeDocumentDomainFilter
;
...
...
@@ -321,19 +320,118 @@ describe('annotation.js', function() {
var
fakeUrlEncodeFilter
;
var
sandbox
;
function
createDirective
()
{
function
createDirective
(
annotation
)
{
annotation
=
annotation
||
defaultAnnotation
();
$scope
.
annotation
=
annotation
;
var
element
=
angular
.
element
(
'<div annotation="annotation">'
);
compileService
()(
element
)(
$scope
);
$scope
.
$digest
();
var
controller
=
element
.
controller
(
'annotation'
);
var
scope
=
element
.
isolateScope
();
return
{
annotation
:
annotation
,
controller
:
controller
,
element
:
element
,
scope
:
scope
};
}
/** Return the default domain model object that createDirective() uses if
* no custom one is passed to it. */
function
defaultAnnotation
()
{
return
{
id
:
'deadbeef'
,
document
:
{
title
:
'A special document'
},
target
:
[{}],
uri
:
'http://example.com'
,
user
:
'acct:bill@localhost'
};
}
/** Return an annotation domain model object for a new annotation
* (newly-created client-side, not yet saved to the server).
*/
function
newAnnotation
()
{
// A new annotation won't have any saved drafts yet.
fakeDrafts
.
get
.
returns
(
null
);
return
{
id
:
undefined
,
$highlight
:
undefined
,
target
:
[
'foo'
,
'bar'
],
references
:
[],
text
:
'Annotation text'
,
tags
:
[
'tag_1'
,
'tag_2'
]
};
}
/** Return an annotation domain model object for a new highlight
* (newly-created client-side, not yet saved to the server).
*/
function
newHighlight
()
{
// A new highlight won't have any saved drafts yet.
fakeDrafts
.
get
.
returns
(
null
);
return
{
id
:
undefined
,
$highlight
:
true
};
}
/** Return an annotation domain model object for an existing annotation
* received from the server.
*/
function
oldAnnotation
()
{
return
{
id
:
'annotation_id'
,
$highlight
:
undefined
,
target
:
[
'foo'
,
'bar'
],
references
:
[],
text
:
'This is my annotation'
,
tags
:
[
'tag_1'
,
'tag_2'
]
};
}
/** Return an annotation domain model object for an existing highlight
* received from the server.
*/
function
oldHighlight
()
{
return
{
id
:
'annotation_id'
,
$highlight
:
undefined
,
target
:
[
'foo'
,
'bar'
],
references
:
[],
text
:
''
,
tags
:
[]
};
}
/** Return an annotation domain model object for an existing page note
* received from the server.
*/
function
oldPageNote
()
{
return
{
highlight
:
undefined
,
target
:
[],
references
:
[],
text
:
''
,
tags
:
[]
};
}
/** Return an annotation domain model object for an existing reply
* received from the server.
*/
function
oldReply
()
{
return
{
highlight
:
undefined
,
target
:
[
'foo'
],
references
:
[
'parent_annotation_id'
],
text
:
''
,
tags
:
[]
};
}
before
(
function
()
{
angular
.
module
(
'h'
,
[])
.
directive
(
'annotation'
,
require
(
'../annotation'
).
directive
);
...
...
@@ -453,15 +551,6 @@ describe('annotation.js', function() {
$timeout
=
_$timeout_
;
$rootScope
=
_$rootScope_
;
$scope
=
$rootScope
.
$new
();
$scope
.
annotation
=
annotation
=
{
id
:
'deadbeef'
,
document
:
{
title
:
'A special document'
},
target
:
[{}],
uri
:
'http://example.com'
,
user
:
'acct:bill@localhost'
};
}
)
);
...
...
@@ -470,6 +559,112 @@ describe('annotation.js', function() {
sandbox
.
restore
();
});
describe
(
'AnnotationController() initialization'
,
function
()
{
it
(
'saves new highlights to the server on initialization'
,
function
()
{
var
annotation
=
newHighlight
();
// The user is logged-in.
annotation
.
user
=
fakeSession
.
state
.
userid
=
'acct:bill@localhost'
;
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
createDirective
(
annotation
);
assert
.
called
(
annotation
.
$create
);
});
it
(
'saves new highlights to drafts if not logged in'
,
function
()
{
var
annotation
=
newHighlight
();
// The user is not logged-in.
annotation
.
user
=
fakeSession
.
state
.
userid
=
undefined
;
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
createDirective
(
annotation
);
assert
.
notCalled
(
annotation
.
$create
);
assert
.
called
(
fakeDrafts
.
update
);
});
it
(
'does not save new annotations on initialization'
,
function
()
{
var
annotation
=
newAnnotation
();
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
createDirective
(
annotation
);
assert
.
notCalled
(
annotation
.
$create
);
});
it
(
'does not save old highlights on initialization'
,
function
()
{
var
annotation
=
oldHighlight
();
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
createDirective
(
annotation
);
assert
.
notCalled
(
annotation
.
$create
);
});
it
(
'does not save old annotations on initialization'
,
function
()
{
var
annotation
=
oldAnnotation
();
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
createDirective
(
annotation
);
assert
.
notCalled
(
annotation
.
$create
);
});
it
(
'edits new annotations on initialization'
,
function
()
{
var
annotation
=
newAnnotation
();
var
controller
=
createDirective
(
annotation
).
controller
;
assert
.
isTrue
(
controller
.
editing
());
});
it
(
'edits annotations with drafts on initialization'
,
function
()
{
var
annotation
=
oldAnnotation
();
// The drafts service has some draft changes for this annotation.
fakeDrafts
.
get
.
returns
(
'foo'
);
var
controller
=
createDirective
(
annotation
).
controller
;
assert
.
isTrue
(
controller
.
editing
());
});
it
(
'does not edit new highlights on initialization'
,
function
()
{
var
annotation
=
newHighlight
();
// We have to set annotation.$create() because it'll try to call it.
annotation
.
$create
=
sandbox
.
stub
().
returns
({
then
:
function
()
{}
});
var
controller
=
createDirective
(
annotation
).
controller
;
assert
.
isFalse
(
controller
.
editing
());
});
it
(
'edits highlights with drafts on initialization'
,
function
()
{
var
annotation
=
oldHighlight
();
// You can edit a highlight, enter some text or tags, and save it (the
// highlight then becomes an annotation). You can also edit a highlight
// and then change focus to another group and back without saving the
// highlight, in which case the highlight will have draft edits.
// This highlight has draft edits.
fakeDrafts
.
get
.
returns
(
'foo'
);
var
controller
=
createDirective
(
annotation
).
controller
;
assert
.
isTrue
(
controller
.
editing
());
});
});
describe
(
'AnnotationController.editing()'
,
function
()
{
it
(
'returns true if action is "create"'
,
function
()
{
var
controller
=
createDirective
().
controller
;
...
...
@@ -490,8 +685,77 @@ describe('annotation.js', function() {
});
});
describe
(
'AnnotationController.isHighlight()'
,
function
()
{
it
(
'returns true for new highlights'
,
function
()
{
var
annotation
=
newHighlight
();
// We need to define $create because it'll try to call it.
annotation
.
$create
=
function
()
{
return
{
then
:
function
()
{}};};
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isTrue
(
vm
.
isHighlight
());
});
it
(
'returns false for new annotations'
,
function
()
{
var
annotation
=
newAnnotation
();
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isFalse
(
vm
.
isHighlight
());
});
it
(
'returns false for page notes'
,
function
()
{
var
annotation
=
oldPageNote
();
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isFalse
(
vm
.
isHighlight
());
});
it
(
'returns false for replies'
,
function
()
{
var
annotation
=
oldReply
();
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isFalse
(
vm
.
isHighlight
());
});
it
(
'returns false for annotations with text but no tags'
,
function
()
{
var
annotation
=
oldAnnotation
();
annotation
.
text
=
'This is my annotation'
;
annotation
.
tags
=
[];
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isFalse
(
vm
.
isHighlight
());
});
it
(
'returns false for annotations with tags but no text'
,
function
()
{
var
annotation
=
oldAnnotation
();
annotation
.
text
=
''
;
annotation
.
tags
=
[
'foo'
];
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isFalse
(
vm
.
isHighlight
());
});
it
(
'returns true for annotations with no text or tags'
,
function
()
{
var
annotation
=
oldAnnotation
();
annotation
.
text
=
''
;
annotation
.
tags
=
[];
var
vm
=
createDirective
(
annotation
).
controller
;
assert
.
isTrue
(
vm
.
isHighlight
());
});
});
describe
(
'when the annotation is a highlight'
,
function
()
{
var
annotation
;
beforeEach
(
function
()
{
annotation
=
defaultAnnotation
();
annotation
.
$highlight
=
true
;
annotation
.
$create
=
sinon
.
stub
().
returns
({
then
:
angular
.
noop
,
...
...
@@ -500,22 +764,9 @@ describe('annotation.js', function() {
});
});
it
(
'persists upon login'
,
function
()
{
delete
annotation
.
id
;
delete
annotation
.
user
;
fakeSession
.
state
.
userid
=
null
;
createDirective
();
$scope
.
$digest
();
assert
.
notCalled
(
annotation
.
$create
);
fakeSession
.
state
.
userid
=
'acct:ted@wyldstallyns.com'
;
$scope
.
$broadcast
(
events
.
USER_CHANGED
,
{});
$scope
.
$digest
();
assert
.
calledOnce
(
annotation
.
$create
);
});
it
(
'is private'
,
function
()
{
delete
annotation
.
id
;
createDirective
();
createDirective
(
annotation
);
$scope
.
$digest
();
assert
.
deepEqual
(
annotation
.
permissions
,
{
read
:
[
'justme'
]
...
...
@@ -524,7 +775,10 @@ describe('annotation.js', function() {
});
describe
(
'#reply'
,
function
()
{
var
annotation
;
beforeEach
(
function
()
{
annotation
=
defaultAnnotation
();
annotation
.
permissions
=
{
read
:
[
'acct:joe@localhost'
],
update
:
[
'acct:joe@localhost'
],
...
...
@@ -534,7 +788,7 @@ describe('annotation.js', function() {
});
it
(
'creates a new reply with the proper uri and references'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
reply
();
var
match
=
sinon
.
match
({
references
:
[
annotation
.
id
],
...
...
@@ -544,7 +798,7 @@ describe('annotation.js', function() {
});
it
(
'makes the annotation shared if the parent is shared'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
var
reply
=
{};
fakeAnnotationMapper
.
createAnnotation
.
returns
(
reply
);
fakePermissions
.
isShared
.
returns
(
true
);
...
...
@@ -555,7 +809,7 @@ describe('annotation.js', function() {
});
it
(
'makes the annotation shared if the parent is shared'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
$scope
.
annotation
.
group
=
'my group'
;
$scope
.
annotation
.
permissions
=
{
read
:
[
'my group'
]
...
...
@@ -577,7 +831,7 @@ describe('annotation.js', function() {
it
(
'does not add the world readable principal if the parent is private'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
var
reply
=
{};
fakeAnnotationMapper
.
createAnnotation
.
returns
(
reply
);
fakePermissions
.
isShared
.
returns
(
false
);
...
...
@@ -589,7 +843,7 @@ describe('annotation.js', function() {
);
it
(
'sets the reply
\'
s group to be the same as its parent
\'
s'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
$scope
.
annotation
.
group
=
'my group'
;
var
reply
=
{};
fakeAnnotationMapper
.
createAnnotation
.
returns
(
reply
);
...
...
@@ -600,58 +854,58 @@ describe('annotation.js', function() {
describe
(
'#setPrivacy'
,
function
()
{
it
(
'makes the annotation private when level is "private"'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
controller
.
edit
();
controller
.
setPrivacy
(
'private'
);
return
controller
.
save
().
then
(
function
()
{
var
parts
=
createDirective
()
;
parts
.
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
parts
.
controller
.
edit
();
parts
.
controller
.
setPrivacy
(
'private'
);
return
parts
.
controller
.
save
().
then
(
function
()
{
// Verify that the permissions are updated once the annotation
// is saved.
assert
.
deepEqual
(
annotation
.
permissions
,
{
assert
.
deepEqual
(
parts
.
annotation
.
permissions
,
{
read
:
[
'justme'
]
});
});
});
it
(
'makes the annotation shared when level is "shared"'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
controller
.
edit
();
controller
.
setPrivacy
(
'shared'
);
return
controller
.
save
().
then
(
function
()
{
assert
.
deepEqual
(
annotation
.
permissions
,
{
var
parts
=
createDirective
()
;
parts
.
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
parts
.
controller
.
edit
();
parts
.
controller
.
setPrivacy
(
'shared'
);
return
parts
.
controller
.
save
().
then
(
function
()
{
assert
.
deepEqual
(
parts
.
annotation
.
permissions
,
{
read
:
[
'everybody'
]
});
});
});
it
(
'saves the "shared" visibility level to localStorage'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
controller
.
edit
();
controller
.
setPrivacy
(
'shared'
);
return
controller
.
save
().
then
(
function
()
{
var
parts
=
createDirective
()
;
parts
.
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
parts
.
controller
.
edit
();
parts
.
controller
.
setPrivacy
(
'shared'
);
return
parts
.
controller
.
save
().
then
(
function
()
{
assert
(
fakePermissions
.
setDefault
.
calledWithExactly
(
'shared'
));
});
});
it
(
'saves the "private" visibility level to localStorage'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
controller
.
edit
();
controller
.
setPrivacy
(
'private'
);
return
controller
.
save
().
then
(
function
()
{
var
parts
=
createDirective
()
;
parts
.
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
parts
.
controller
.
edit
();
parts
.
controller
.
setPrivacy
(
'private'
);
return
parts
.
controller
.
save
().
then
(
function
()
{
assert
(
fakePermissions
.
setDefault
.
calledWithExactly
(
'private'
));
});
});
it
(
'doesn
\'
t save the visibility if the annotation is a reply'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
annotation
.
references
=
[
'parent id'
];
controller
.
edit
();
controller
.
setPrivacy
(
'private'
);
return
controller
.
save
().
then
(
function
()
{
var
parts
=
createDirective
()
;
parts
.
annotation
.
$update
=
sinon
.
stub
().
returns
(
Promise
.
resolve
());
parts
.
annotation
.
references
=
[
'parent id'
];
parts
.
controller
.
edit
();
parts
.
controller
.
setPrivacy
(
'private'
);
return
parts
.
controller
.
save
().
then
(
function
()
{
assert
(
!
fakePermissions
.
setDefault
.
called
);
});
});
...
...
@@ -707,15 +961,15 @@ describe('annotation.js', function() {
});
it
(
'is called exactly once on model changes'
,
function
()
{
var
controller
=
createDirective
().
controller
;
sandbox
.
spy
(
controller
,
'render'
);
assert
.
notCalled
(
controller
.
render
);
annotation
[
'delete'
]
=
true
;
var
parts
=
createDirective
()
;
sandbox
.
spy
(
parts
.
controller
,
'render'
);
assert
.
notCalled
(
parts
.
controller
.
render
);
parts
.
annotation
[
'delete'
]
=
true
;
$scope
.
$digest
();
assert
.
calledOnce
(
controller
.
render
);
annotation
.
booz
=
'baz'
;
assert
.
calledOnce
(
parts
.
controller
.
render
);
parts
.
annotation
.
booz
=
'baz'
;
$scope
.
$digest
();
assert
.
calledTwice
(
controller
.
render
);
assert
.
calledTwice
(
parts
.
controller
.
render
);
});
it
(
'provides a document title'
,
function
()
{
...
...
@@ -725,18 +979,18 @@ describe('annotation.js', function() {
});
it
(
'uses the first title when there are more than one'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
document
.
title
=
[
'first title'
,
'second title'
];
controller
.
render
();
assert
.
equal
(
controller
.
document
.
title
,
'first title'
);
var
parts
=
createDirective
()
;
parts
.
annotation
.
document
.
title
=
[
'first title'
,
'second title'
];
parts
.
controller
.
render
();
assert
.
equal
(
parts
.
controller
.
document
.
title
,
'first title'
);
});
it
(
'truncates long titles'
,
function
()
{
var
controller
=
createDirective
().
controller
;
annotation
.
document
.
title
=
'A very very very long title that really
\
nshouldn
\'
t be found on a page on the internet.'
;
controller
.
render
();
var
parts
=
createDirective
()
;
parts
.
annotation
.
document
.
title
=
'A very very very long title that really
\
nshouldn
\'
t be found on a page on the internet.'
;
parts
.
controller
.
render
();
assert
.
equal
(
controller
.
document
.
title
,
'A very very very long title th…'
);
parts
.
controller
.
document
.
title
,
'A very very very long title th…'
);
});
it
(
'provides a document uri'
,
function
()
{
...
...
@@ -752,47 +1006,49 @@ describe('annotation.js', function() {
});
it
(
'uses the domain for the title if the title is not present'
,
function
()
{
var
controller
=
createDirective
().
controller
;
delete
annotation
.
document
.
title
;
controller
.
render
();
assert
.
equal
(
controller
.
document
.
title
,
'example.com'
);
var
parts
=
createDirective
()
;
delete
parts
.
annotation
.
document
.
title
;
parts
.
controller
.
render
();
assert
.
equal
(
parts
.
controller
.
document
.
title
,
'example.com'
);
});
it
(
'still sets the uri correctly if the annotation has no document'
,
function
()
{
var
controller
=
createDirective
().
controller
;
delete
annotation
.
document
;
controller
.
render
();
assert
(
controller
.
document
.
uri
===
$scope
.
annotation
.
uri
);
var
parts
=
createDirective
()
;
delete
parts
.
annotation
.
document
;
parts
.
controller
.
render
();
assert
(
parts
.
controller
.
document
.
uri
===
$scope
.
annotation
.
uri
);
}
);
it
(
'still sets the domain correctly if the annotation has no document'
,
function
()
{
var
controller
=
createDirective
().
controller
;
delete
annotation
.
document
;
controller
.
render
();
assert
(
controller
.
document
.
domain
===
'example.com'
);
var
parts
=
createDirective
()
;
delete
parts
.
annotation
.
document
;
parts
.
controller
.
render
();
assert
(
parts
.
controller
.
document
.
domain
===
'example.com'
);
}
);
it
(
'uses the domain for the title when the annotation has no document'
,
function
()
{
var
controller
=
createDirective
().
controller
;
delete
annotation
.
document
;
controller
.
render
();
assert
(
controller
.
document
.
title
===
'example.com'
);
var
parts
=
createDirective
()
;
delete
parts
.
annotation
.
document
;
parts
.
controller
.
render
();
assert
(
parts
.
controller
.
document
.
title
===
'example.com'
);
}
);
describe
(
'timestamp'
,
function
()
{
var
annotation
;
var
clock
;
beforeEach
(
function
()
{
clock
=
sinon
.
useFakeTimers
();
annotation
=
defaultAnnotation
();
annotation
.
created
=
(
new
Date
()).
toString
();
annotation
.
updated
=
(
new
Date
()).
toString
();
});
...
...
@@ -803,7 +1059,7 @@ describe('annotation.js', function() {
it
(
'is not updated for unsaved annotations'
,
function
()
{
annotation
.
updated
=
null
;
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
// Unsaved annotations don't have an updated time yet so a timestamp
// string can't be computed for them.
$scope
.
$digest
();
...
...
@@ -811,13 +1067,13 @@ describe('annotation.js', function() {
});
it
(
'is updated on first digest'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
$scope
.
$digest
();
assert
.
equal
(
controller
.
timestamp
,
'a while ago'
);
});
it
(
'is updated after a timeout'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
fakeTime
.
nextFuzzyUpdate
.
returns
(
10
);
fakeTime
.
toFuzzyString
.
returns
(
'ages ago'
);
$scope
.
$digest
();
...
...
@@ -827,7 +1083,7 @@ describe('annotation.js', function() {
});
it
(
'is no longer updated after the scope is destroyed'
,
function
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
$scope
.
$digest
();
$scope
.
$destroy
();
$timeout
.
flush
();
...
...
@@ -837,13 +1093,10 @@ describe('annotation.js', function() {
describe
(
'share'
,
function
()
{
it
(
'sets and unsets the open class on the share wrapper'
,
function
()
{
var
components
=
createDirective
();
var
controller
=
components
.
controller
;
var
element
=
components
.
element
;
var
scope
=
components
.
scope
;
var
dialog
=
element
.
find
(
'.share-dialog-wrapper'
);
var
parts
=
createDirective
();
var
dialog
=
parts
.
element
.
find
(
'.share-dialog-wrapper'
);
dialog
.
find
(
'button'
).
click
();
scope
.
$digest
();
parts
.
scope
.
$digest
();
assert
.
ok
(
dialog
.
hasClass
(
'open'
));
documentService
().
click
();
assert
.
notOk
(
dialog
.
hasClass
(
'open'
));
...
...
@@ -860,11 +1113,13 @@ describe('annotation.js', function() {
it
(
'calls annotationMapper.delete() if the delete is confirmed'
,
function
(
done
)
{
var
controller
=
createDirective
().
controller
;
var
parts
=
createDirective
()
;
sandbox
.
stub
(
$window
,
'confirm'
).
returns
(
true
);
fakeAnnotationMapper
.
deleteAnnotation
.
returns
(
$q
.
resolve
());
controller
[
'delete'
]().
then
(
function
()
{
assert
(
fakeAnnotationMapper
.
deleteAnnotation
.
calledWith
(
annotation
));
parts
.
controller
[
'delete'
]().
then
(
function
()
{
assert
(
fakeAnnotationMapper
.
deleteAnnotation
.
calledWith
(
parts
.
annotation
));
done
();
});
$timeout
.
flush
();
...
...
@@ -926,13 +1181,16 @@ describe('annotation.js', function() {
});
describe
(
'saving a new annotation'
,
function
()
{
var
annotation
;
beforeEach
(
function
()
{
fakeFlash
.
error
=
sandbox
.
stub
();
annotation
=
defaultAnnotation
();
annotation
.
$create
=
sandbox
.
stub
();
});
function
controllerWithActionCreate
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
action
=
'create'
;
return
controller
;
}
...
...
@@ -994,13 +1252,16 @@ describe('annotation.js', function() {
});
describe
(
'saving an edited an annotation'
,
function
()
{
var
annotation
;
beforeEach
(
function
()
{
fakeFlash
.
error
=
sandbox
.
stub
();
annotation
=
defaultAnnotation
();
annotation
.
$update
=
sandbox
.
stub
();
});
function
controllerWithActionEdit
()
{
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
action
=
'edit'
;
return
controller
;
}
...
...
@@ -1050,9 +1311,9 @@ describe('annotation.js', function() {
describe
(
'drafts'
,
function
()
{
it
(
'creates a draft when editing an annotation'
,
function
()
{
var
controller
=
createDirective
().
controller
;
controller
.
edit
();
assert
.
calledWith
(
fakeDrafts
.
update
,
annotation
);
var
parts
=
createDirective
()
;
parts
.
controller
.
edit
();
assert
.
calledWith
(
fakeDrafts
.
update
,
parts
.
annotation
);
});
it
(
...
...
@@ -1062,14 +1323,15 @@ describe('annotation.js', function() {
// "changes" object that aren't actually set on the annotation. In this
// case, both permissions and tags are null so shouldn't be saved in
// the draft.
var
controller
=
createDirective
().
controller
;
annotation
.
permissions
=
null
;
annotation
.
text
=
'Hello!'
;
annotation
.
tags
=
null
;
var
parts
=
createDirective
()
;
parts
.
annotation
.
permissions
=
null
;
parts
.
annotation
.
text
=
'Hello!'
;
parts
.
annotation
.
tags
=
null
;
controller
.
edit
();
parts
.
controller
.
edit
();
assert
.
calledWith
(
fakeDrafts
.
update
,
annotation
,
{
text
:
'Hello!'
});
assert
.
calledWith
(
fakeDrafts
.
update
,
parts
.
annotation
,
{
text
:
'Hello!'
});
}
);
...
...
@@ -1101,15 +1363,16 @@ describe('annotation.js', function() {
});
it
(
'removes the draft when changes are discarded'
,
function
()
{
var
controller
=
createDirective
().
controller
;
controller
.
edit
();
controller
.
revert
();
assert
.
calledWith
(
fakeDrafts
.
remove
,
annotation
);
var
parts
=
createDirective
()
;
parts
.
controller
.
edit
();
parts
.
controller
.
revert
();
assert
.
calledWith
(
fakeDrafts
.
remove
,
parts
.
annotation
);
});
it
(
'removes the draft when changes are saved'
,
function
()
{
var
annotation
=
defaultAnnotation
();
annotation
.
$update
=
sandbox
.
stub
().
returns
(
Promise
.
resolve
());
var
controller
=
createDirective
().
controller
;
var
controller
=
createDirective
(
annotation
).
controller
;
controller
.
edit
();
controller
.
save
();
...
...
@@ -1125,17 +1388,17 @@ describe('annotation.js', function() {
describe
(
'when the focused group changes'
,
function
()
{
it
(
'updates the current draft'
,
function
()
{
var
controller
=
createDirective
().
controller
;
controller
.
edit
();
controller
.
annotation
.
text
=
'unsaved-text'
;
controller
.
annotation
.
tags
=
[];
controller
.
annotation
.
permissions
=
'new permissions'
;
var
parts
=
createDirective
()
;
parts
.
controller
.
edit
();
parts
.
controller
.
annotation
.
text
=
'unsaved-text'
;
parts
.
controller
.
annotation
.
tags
=
[];
parts
.
controller
.
annotation
.
permissions
=
'new permissions'
;
fakeDrafts
.
get
=
sinon
.
stub
().
returns
({
text
:
'old-draft'
});
fakeDrafts
.
update
=
sinon
.
stub
();
$rootScope
.
$broadcast
(
events
.
GROUP_FOCUSED
);
assert
.
calledWith
(
fakeDrafts
.
update
,
annotation
,
{
assert
.
calledWith
(
fakeDrafts
.
update
,
parts
.
annotation
,
{
text
:
'unsaved-text'
,
tags
:
[],
permissions
:
'new permissions'
...
...
@@ -1152,8 +1415,9 @@ describe('annotation.js', function() {
});
it
(
'moves new annotations to the focused group'
,
function
()
{
var
annotation
=
defaultAnnotation
();
annotation
.
id
=
null
;
createDirective
();
createDirective
(
annotation
);
fakeGroups
.
focused
=
sinon
.
stub
().
returns
({
id
:
'new-group'
});
...
...
@@ -1167,6 +1431,7 @@ describe('annotation.js', function() {
function
()
{
// id must be null so that AnnotationController considers this a new
// annotation.
var
annotation
=
defaultAnnotation
();
annotation
.
id
=
null
;
annotation
.
group
=
'old-group'
;
annotation
.
permissions
=
{
...
...
@@ -1174,7 +1439,7 @@ describe('annotation.js', function() {
};
// This is a shared annotation.
fakePermissions
.
isShared
.
returns
(
true
);
createDirective
();
createDirective
(
annotation
);
// Make permissions.shared() behave like we expect it to.
fakePermissions
.
shared
=
function
(
groupId
)
{
return
{
...
...
@@ -1192,6 +1457,7 @@ describe('annotation.js', function() {
it
(
'saves shared permissions for the new group to drafts'
,
function
()
{
// id must be null so that AnnotationController considers this a new
// annotation.
var
annotation
=
defaultAnnotation
();
annotation
.
id
=
null
;
annotation
.
group
=
'old-group'
;
annotation
.
permissions
=
{
...
...
@@ -1199,7 +1465,7 @@ describe('annotation.js', function() {
};
// This is a shared annotation.
fakePermissions
.
isShared
.
returns
(
true
);
createDirective
();
createDirective
(
annotation
);
// drafts.get() needs to return something truthy, otherwise
// AnnotationController won't try to update the draft for the annotation.
fakeDrafts
.
get
.
returns
(
true
);
...
...
@@ -1223,12 +1489,13 @@ describe('annotation.js', function() {
it
(
'does not change perms when moving new private annotations'
,
function
()
{
// id must be null so that AnnotationController considers this a new
// annotation.
var
annotation
=
defaultAnnotation
();
annotation
.
id
=
null
;
annotation
.
group
=
'old-group'
;
annotation
.
permissions
=
{
read
:
[
'acct:bill@localhost'
]
};
createDirective
();
createDirective
(
annotation
);
// This is a private annotation.
fakePermissions
.
isShared
.
returns
(
false
);
fakeGroups
.
focused
=
sinon
.
stub
().
returns
({
...
...
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