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
5b36b58c
Commit
5b36b58c
authored
Mar 28, 2017
by
Sean Hammond
Committed by
GitHub
Mar 28, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #314 from hypothesis/stream-content-component
Convert StreamController to a component
parents
f4b00536
ba2b95f4
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
247 additions
and
217 deletions
+247
-217
app.js
src/sidebar/app.js
+2
-3
stream-content.js
src/sidebar/components/stream-content.js
+91
-0
stream-content-test.js
src/sidebar/components/test/stream-content-test.js
+150
-0
stream-controller.coffee
src/sidebar/stream-controller.coffee
+0
-73
stream_content.html
src/sidebar/templates/stream_content.html
+4
-4
stream-controller-test.coffee
src/sidebar/test/stream-controller-test.coffee
+0
-137
No files found.
src/sidebar/app.js
View file @
5b36b58c
...
...
@@ -69,8 +69,7 @@ function configureRoutes($routeProvider) {
});
$routeProvider
.
when
(
'/stream'
,
{
controller
:
'StreamController'
,
template
:
require
(
'./templates/stream_content.html'
),
template
:
'<stream-content search="search"></stream-content>'
,
reloadOnSearch
:
false
,
resolve
:
resolve
,
});
...
...
@@ -130,7 +129,6 @@ module.exports = angular.module('h', [
])
.
controller
(
'AnnotationViewerController'
,
require
(
'./annotation-viewer-controller'
))
.
controller
(
'StreamController'
,
require
(
'./stream-controller'
))
// The root component for the application
.
directive
(
'hypothesisApp'
,
require
(
'./directive/app'
))
...
...
@@ -156,6 +154,7 @@ module.exports = angular.module('h', [
.
component
(
'sidebarTutorial'
,
require
(
'./components/sidebar-tutorial'
).
component
)
.
component
(
'shareDialog'
,
require
(
'./components/share-dialog'
))
.
component
(
'sortDropdown'
,
require
(
'./components/sort-dropdown'
))
.
component
(
'streamContent'
,
require
(
'./components/stream-content'
))
.
component
(
'svgIcon'
,
require
(
'./components/svg-icon'
))
.
component
(
'tagEditor'
,
require
(
'./components/tag-editor'
))
.
component
(
'threadList'
,
require
(
'./components/thread-list'
))
...
...
src/sidebar/components/stream-content.js
0 → 100644
View file @
5b36b58c
'use strict'
;
// @ngInject
function
StreamContentController
(
$scope
,
$location
,
$route
,
$routeParams
,
annotationMapper
,
annotationUI
,
queryParser
,
rootThread
,
searchFilter
,
store
,
streamFilter
,
streamer
)
{
var
self
=
this
;
annotationUI
.
setAppIsSidebar
(
false
);
/** `offset` parameter for the next search API call. */
var
offset
=
0
;
/** Load annotations fetched from the API into the app. */
var
load
=
function
(
result
)
{
offset
+=
result
.
rows
.
length
;
annotationMapper
.
loadAnnotations
(
result
.
rows
,
result
.
replies
);
};
/**
* Fetch the next `limit` annotations starting from `offset` from the API.
*/
var
fetch
=
function
(
limit
)
{
var
query
=
Object
.
assign
({
_separate_replies
:
true
,
offset
:
offset
,
limit
:
limit
,
},
searchFilter
.
toObject
(
$routeParams
.
q
));
store
.
search
(
query
)
.
then
(
load
)
.
catch
(
function
(
err
)
{
console
.
error
(
err
);
});
};
// Re-do search when query changes
var
lastQuery
=
$routeParams
.
q
;
$scope
.
$on
(
'$routeUpdate'
,
function
()
{
if
(
$routeParams
.
q
!==
lastQuery
)
{
annotationUI
.
clearAnnotations
();
$route
.
reload
();
}
});
// Set up updates from real-time API.
streamFilter
.
resetFilter
()
.
setMatchPolicyIncludeAll
();
var
terms
=
searchFilter
.
generateFacetedFilter
(
$routeParams
.
q
);
queryParser
.
populateFilter
(
streamFilter
,
terms
);
streamer
.
setConfig
(
'filter'
,
{
filter
:
streamFilter
.
getFilter
()});
streamer
.
connect
();
// Perform the initial search
fetch
(
20
);
this
.
setCollapsed
=
annotationUI
.
setCollapsed
;
this
.
forceVisible
=
function
(
id
)
{
annotationUI
.
setForceVisible
(
id
,
true
);
};
Object
.
assign
(
this
.
search
,
{
query
:
function
()
{
return
$routeParams
.
q
||
''
;
},
update
:
function
(
q
)
{
$location
.
search
({
q
:
q
});
},
});
annotationUI
.
subscribe
(
function
()
{
self
.
rootThread
=
rootThread
.
thread
(
annotationUI
.
getState
());
});
// Sort the stream so that the newest annotations are at the top
annotationUI
.
setSortKey
(
'Newest'
);
this
.
loadMore
=
fetch
;
}
module
.
exports
=
{
controller
:
StreamContentController
,
controllerAs
:
'vm'
,
bindings
:
{
search
:
'<'
,
},
template
:
require
(
'../templates/stream_content.html'
),
};
src/sidebar/components/test/stream-content-test.js
0 → 100644
View file @
5b36b58c
'use strict'
;
var
angular
=
require
(
'angular'
);
var
inherits
=
require
(
'inherits'
);
var
EventEmitter
=
require
(
'tiny-emitter'
);
function
FakeRootThread
()
{
this
.
thread
=
sinon
.
stub
();
}
inherits
(
FakeRootThread
,
EventEmitter
);
describe
(
'StreamContentController'
,
function
()
{
var
$componentController
;
var
$rootScope
;
var
fakeRoute
;
var
fakeRouteParams
;
var
fakeAnnotationMapper
;
var
fakeAnnotationUI
;
var
fakeQueryParser
;
var
fakeRootThread
;
var
fakeSearchFilter
;
var
fakeStore
;
var
fakeStreamer
;
var
fakeStreamFilter
;
before
(
function
()
{
angular
.
module
(
'h'
,
[])
.
component
(
'streamContent'
,
require
(
'../stream-content'
));
});
beforeEach
(
function
()
{
fakeAnnotationMapper
=
{
loadAnnotations
:
sinon
.
spy
(),
};
fakeAnnotationUI
=
{
clearAnnotations
:
sinon
.
spy
(),
setAppIsSidebar
:
sinon
.
spy
(),
setCollapsed
:
sinon
.
spy
(),
setForceVisible
:
sinon
.
spy
(),
setSortKey
:
sinon
.
spy
(),
subscribe
:
sinon
.
spy
(),
};
fakeRouteParams
=
{
id
:
'test'
};
fakeQueryParser
=
{
populateFilter
:
sinon
.
spy
(),
};
fakeRoute
=
{
reload
:
sinon
.
spy
(),
};
fakeSearchFilter
=
{
generateFacetedFilter
:
sinon
.
stub
(),
toObject
:
sinon
.
stub
().
returns
({}),
};
fakeStore
=
{
search
:
sinon
.
spy
(
function
()
{
return
Promise
.
resolve
({
rows
:
[],
total
:
0
});
}),
};
fakeStreamer
=
{
open
:
sinon
.
spy
(),
close
:
sinon
.
spy
(),
setConfig
:
sinon
.
spy
(),
connect
:
sinon
.
spy
(),
};
fakeStreamFilter
=
{
resetFilter
:
sinon
.
stub
().
returnsThis
(),
setMatchPolicyIncludeAll
:
sinon
.
stub
().
returnsThis
(),
getFilter
:
sinon
.
stub
(),
};
fakeRootThread
=
new
FakeRootThread
();
angular
.
mock
.
module
(
'h'
,
{
$route
:
fakeRoute
,
$routeParams
:
fakeRouteParams
,
annotationMapper
:
fakeAnnotationMapper
,
annotationUI
:
fakeAnnotationUI
,
queryParser
:
fakeQueryParser
,
rootThread
:
fakeRootThread
,
searchFilter
:
fakeSearchFilter
,
store
:
fakeStore
,
streamFilter
:
fakeStreamFilter
,
streamer
:
fakeStreamer
,
});
angular
.
mock
.
inject
(
function
(
_$componentController_
,
_$rootScope_
)
{
$componentController
=
_$componentController_
;
$rootScope
=
_$rootScope_
;
});
});
function
createController
()
{
return
$componentController
(
'streamContent'
,
{},
{
search
:
{
query
:
sinon
.
stub
(),
update
:
sinon
.
stub
(),
},
});
}
it
(
'calls the search API with `_separate_replies: true`'
,
function
()
{
createController
();
assert
.
equal
(
fakeStore
.
search
.
firstCall
.
args
[
0
].
_separate_replies
,
true
);
});
it
(
'passes the annotations and replies from search to loadAnnotations()'
,
function
()
{
fakeStore
.
search
=
function
()
{
return
Promise
.
resolve
({
'rows'
:
[
'annotation_1'
,
'annotation_2'
],
'replies'
:
[
'reply_1'
,
'reply_2'
,
'reply_3'
],
});
};
createController
();
Promise
.
resolve
().
then
(
function
()
{
assert
.
calledOnce
(
fakeAnnotationMapper
.
loadAnnotations
);
assert
.
calledWith
(
fakeAnnotationMapper
.
loadAnnotations
,
[
'annotation_1'
,
'annotation_2'
],
[
'reply_1'
,
'reply_2'
,
'reply_3'
]);
});
});
context
(
'when a $routeUpdate event occurs'
,
function
()
{
it
(
'reloads the route if the query changed'
,
function
()
{
fakeRouteParams
.
q
=
'test query'
;
createController
();
fakeRouteParams
.
q
=
'new query'
;
$rootScope
.
$broadcast
(
'$routeUpdate'
);
assert
.
called
(
fakeAnnotationUI
.
clearAnnotations
);
assert
.
calledOnce
(
fakeRoute
.
reload
);
});
it
(
'does not reload the route if the query did not change'
,
function
()
{
fakeRouteParams
.
q
=
'test query'
;
createController
();
$rootScope
.
$broadcast
(
'$routeUpdate'
);
assert
.
notCalled
(
fakeAnnotationUI
.
clearAnnotations
);
assert
.
notCalled
(
fakeRoute
.
reload
);
});
});
});
src/sidebar/stream-controller.coffee
deleted
100644 → 0
View file @
f4b00536
angular
=
require
(
'angular'
)
module
.
exports
=
class
StreamController
this
.
$inject
=
[
'$scope'
,
'$location'
,
'$route'
,
'$rootScope'
,
'$routeParams'
,
'annotationUI'
,
'queryParser'
,
'rootThread'
,
'searchFilter'
,
'store'
,
'streamer'
,
'streamFilter'
,
'annotationMapper'
]
constructor
:
(
$scope
,
$location
,
$route
,
$rootScope
,
$routeParams
annotationUI
,
queryParser
,
rootThread
,
searchFilter
,
store
,
streamer
,
streamFilter
,
annotationMapper
)
->
annotationUI
.
setAppIsSidebar
(
false
)
offset
=
0
fetch
=
(
limit
)
->
options
=
{
offset
,
limit
}
searchParams
=
searchFilter
.
toObject
(
$routeParams
.
q
)
query
=
angular
.
extend
(
options
,
searchParams
)
query
.
_separate_replies
=
true
store
.
search
(
query
)
.
then
(
load
)
.
catch
((
err
)
->
console
.
error
err
)
load
=
({
rows
,
replies
})
->
offset
+=
rows
.
length
annotationMapper
.
loadAnnotations
(
rows
,
replies
)
# Reload on query change (ignore hash change)
lastQuery
=
$routeParams
.
q
$scope
.
$on
'$routeUpdate'
,
->
if
$routeParams
.
q
isnt
lastQuery
annotationUI
.
clearAnnotations
()
$route
.
reload
()
# Initialize the base filter
streamFilter
.
resetFilter
()
.
setMatchPolicyIncludeAll
()
# Apply query clauses
terms
=
searchFilter
.
generateFacetedFilter
$routeParams
.
q
queryParser
.
populateFilter
streamFilter
,
terms
streamer
.
setConfig
(
'filter'
,
{
filter
:
streamFilter
.
getFilter
()})
streamer
.
connect
()
# Perform the initial search
fetch
(
20
)
$scope
.
setCollapsed
=
(
id
,
collapsed
)
->
annotationUI
.
setCollapsed
(
id
,
collapsed
)
$scope
.
forceVisible
=
(
id
)
->
annotationUI
.
setForceVisible
(
id
,
true
)
Object
.
assign
$scope
.
search
,
{
query
:
->
$routeParams
.
q
||
''
update
:
(
q
)
->
$location
.
search
({
q
:
q
})
}
annotationUI
.
subscribe
(
->
$scope
.
rootThread
=
rootThread
.
thread
(
annotationUI
.
getState
())
);
# Sort the stream so that the newest annotations are at the top
annotationUI
.
setSortKey
(
'Newest'
)
$scope
.
isStream
=
true
$scope
.
loadMore
=
fetch
src/sidebar/templates/stream_content.html
View file @
5b36b58c
<span
window-scroll=
"loadMore(20)"
>
<span
window-scroll=
"
vm.
loadMore(20)"
>
<thread-list
on-change-collapsed=
"setCollapsed(id, collapsed)"
on-force-visible=
"forceVisible(thread)"
on-change-collapsed=
"
vm.
setCollapsed(id, collapsed)"
on-force-visible=
"
vm.
forceVisible(thread)"
show-document-info=
"true"
thread=
"rootThread"
>
thread=
"
vm.
rootThread"
>
</thread-list>
</span>
src/sidebar/test/stream-controller-test.coffee
deleted
100644 → 0
View file @
f4b00536
EventEmitter
=
require
(
'tiny-emitter'
)
inherits
=
require
(
'inherits'
)
{
module
,
inject
}
=
angular
.
mock
class
FakeRootThread
extends
EventEmitter
constructor
:
()
->
this
.
thread
=
sinon
.
stub
()
describe
'StreamController'
,
->
$controller
=
null
$scope
=
null
fakeAnnotationMapper
=
null
fakeAnnotationUI
=
null
fakeParams
=
null
fakeQueryParser
=
null
fakeRoute
=
null
fakeStore
=
null
fakeStreamer
=
null
fakeStreamFilter
=
null
fakeThreading
=
null
sandbox
=
null
createController
=
->
$controller
(
'StreamController'
,
{
$scope
:
$scope
})
before
->
angular
.
module
(
'h'
,
[])
.
controller
(
'StreamController'
,
require
(
'../stream-controller'
))
beforeEach
module
(
'h'
)
beforeEach
module
(
$provide
)
->
sandbox
=
sinon
.
sandbox
.
create
()
fakeAnnotationMapper
=
{
loadAnnotations
:
sandbox
.
spy
()
}
fakeAnnotationUI
=
{
clearAnnotations
:
sandbox
.
spy
()
setAppIsSidebar
:
sandbox
.
spy
()
setCollapsed
:
sandbox
.
spy
()
setForceVisible
:
sandbox
.
spy
()
setSortKey
:
sandbox
.
spy
()
subscribe
:
sandbox
.
spy
()
}
fakeParams
=
{
id
:
'test'
}
fakeQueryParser
=
{
populateFilter
:
sandbox
.
spy
()
}
fakeRoute
=
{
reload
:
sandbox
.
spy
()
}
fakeSearchFilter
=
{
generateFacetedFilter
:
sandbox
.
stub
()
toObject
:
sandbox
.
stub
().
returns
({})
}
fakeStore
=
{
search
:
sandbox
.
spy
(
->
Promise
.
resolve
({
rows
:
[],
total
:
0
}))
}
fakeStreamer
=
{
open
:
sandbox
.
spy
()
close
:
sandbox
.
spy
()
setConfig
:
sandbox
.
spy
()
connect
:
sandbox
.
spy
()
}
fakeStreamFilter
=
{
resetFilter
:
sandbox
.
stub
().
returnsThis
()
setMatchPolicyIncludeAll
:
sandbox
.
stub
().
returnsThis
()
getFilter
:
sandbox
.
stub
()
}
fakeRootThread
=
new
FakeRootThread
()
$provide
.
value
'annotationMapper'
,
fakeAnnotationMapper
$provide
.
value
'annotationUI'
,
fakeAnnotationUI
$provide
.
value
'$route'
,
fakeRoute
$provide
.
value
'$routeParams'
,
fakeParams
$provide
.
value
'queryParser'
,
fakeQueryParser
$provide
.
value
'rootThread'
,
fakeRootThread
$provide
.
value
'searchFilter'
,
fakeSearchFilter
$provide
.
value
'store'
,
fakeStore
$provide
.
value
'streamer'
,
fakeStreamer
$provide
.
value
'streamFilter'
,
fakeStreamFilter
return
beforeEach
inject
(
_$controller_
,
$rootScope
)
->
$controller
=
_$controller_
$scope
=
$rootScope
.
$new
()
$scope
.
search
=
{}
afterEach
->
sandbox
.
restore
()
it
'calls the search API with _separate_replies: true'
,
->
createController
()
assert
.
equal
(
fakeStore
.
search
.
firstCall
.
args
[
0
].
_separate_replies
,
true
)
it
'passes the annotations and replies from search to loadAnnotations()'
,
->
fakeStore
.
search
=
(
query
)
->
Promise
.
resolve
({
'rows'
:
[
'annotation_1'
,
'annotation_2'
]
'replies'
:
[
'reply_1'
,
'reply_2'
,
'reply_3'
]
})
createController
()
Promise
.
resolve
().
then
->
assert
.
calledOnce
fakeAnnotationMapper
.
loadAnnotations
assert
.
calledWith
fakeAnnotationMapper
.
loadAnnotations
,
[
'annotation_1'
,
'annotation_2'
],
[
'reply_1'
,
'reply_2'
,
'reply_3'
]
describe
'on $routeUpdate'
,
->
it
'reloads the route when the query changes'
,
->
fakeParams
.
q
=
'test query'
createController
()
fakeParams
.
q
=
'new query'
$scope
.
$broadcast
(
'$routeUpdate'
)
assert
.
called
(
fakeAnnotationUI
.
clearAnnotations
)
assert
.
calledOnce
(
fakeRoute
.
reload
)
it
'does not reload the route when the query is the same'
,
->
fakeParams
.
q
=
'test query'
createController
()
$scope
.
$broadcast
(
'$routeUpdate'
)
assert
.
notCalled
(
fakeRoute
.
reload
)
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