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
9d6fb43f
Commit
9d6fb43f
authored
Jul 14, 2014
by
Ujvari Gergely
Committed by
gergely-ujvari
Jul 29, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Simplified page search
parent
1edc0a9e
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
303 additions
and
134 deletions
+303
-134
controllers.coffee
h/static/scripts/controllers.coffee
+21
-24
directives.coffee
h/static/scripts/directives.coffee
+16
-2
displayer.coffee
h/static/scripts/displayer.coffee
+1
-1
searchfilters.coffee
h/static/scripts/searchfilters.coffee
+114
-1
services.coffee
h/static/scripts/services.coffee
+150
-105
streamsearch.coffee
h/static/scripts/streamsearch.coffee
+1
-1
No files found.
h/static/scripts/controllers.coffee
View file @
9d6fb43f
...
...
@@ -2,7 +2,7 @@ imports = [
'bootstrap'
'h.helpers'
'h.socket'
'h.s
treamfilter
'
'h.s
earchfilters
'
]
SEARCH_FACETS
=
[
'text'
,
'tags'
,
'uri'
,
'quote'
,
'since'
,
'user'
,
'results'
]
...
...
@@ -228,6 +228,16 @@ class App
$rootScope
.
applySort
"Location"
$scope
.
query
=
$location
.
search
()
$scope
.
searchFacets
=
SEARCH_FACETS
$scope
.
searchValues
=
SEARCH_VALUES
$scope
.
search
=
{}
$scope
.
search
.
update
=
angular
.
noop
$scope
.
search
.
clear
=
angular
.
noop
#$scope.show_search = Object.keys($scope.query).length > 0
$rootScope
.
$on
'$routeChangeSuccess'
,
(
event
,
next
,
current
)
->
unless
next
.
$
$route
?
then
return
...
...
@@ -237,27 +247,8 @@ class App
$scope
.
search
.
update
=
(
searchCollection
)
->
return
unless
annotator
.
discardDrafts
()
return
unless
searchCollection
.
models
.
length
models
=
searchCollection
.
models
matched
=
[]
query
=
tags
:
[]
quote
:
[]
for
item
in
models
{
category
,
value
}
=
item
.
attributes
# Stuff we need to collect
switch
when
category
in
[
'text'
,
'user'
,
'time'
,
'group'
]
query
[
category
]
=
value
when
category
==
'tags'
# Tags are specials, because we collect those into an array
query
.
tags
.
push
value
.
toLowerCase
()
when
category
==
'quote'
query
.
quote
=
query
.
quote
.
concat
(
value
.
split
(
/\s+/
))
query
=
{
query
:
searchCollection
}
unless
angular
.
equals
$location
.
search
(),
query
if
$location
.
path
()
==
'/viewer'
$location
.
path
(
'/page_search'
).
search
(
query
)
...
...
@@ -846,12 +837,18 @@ class Search
refresh
()
refresh
=
=>
$scope
.
matches
=
viewFilter
.
filter
$rootScope
.
annotations
,
$routeParams
[
$scope
.
matches
,
$scope
.
filters
]
=
viewFilter
.
filter
$rootScope
.
annotations
,
$routeParams
# Create the regexps for highlighting the matches inside the annotations' bodies
$scope
.
text_tokens
=
$
routeParams
.
text
?
.
split
(
/\s+/
)
or
[]
$scope
.
text_tokens
=
$
scope
.
filters
.
text
.
terms
.
slice
()
$scope
.
text_regexp
=
[]
$scope
.
quote_tokens
=
$
routeParams
.
quote
$scope
.
quote_tokens
=
$
scope
.
filters
.
quote
.
terms
.
slice
()
$scope
.
quote_regexp
=
[]
# Highligh any matches
for
term
in
$scope
.
filters
.
any
.
terms
$scope
.
text_tokens
.
push
term
$scope
.
quote_tokens
.
push
term
# Saving the regexps and higlighter to the annotator for highlighttext regeneration
for
token
in
$scope
.
text_tokens
regexp
=
new
RegExp
(
token
,
"ig"
)
...
...
h/static/scripts/directives.coffee
View file @
9d6fb43f
...
...
@@ -326,11 +326,10 @@ username = ['$filter', '$window', ($filter, $window) ->
link
:
(
scope
,
elem
,
attr
)
->
scope
.
$watch
'user'
,
->
scope
.
uname
=
$filter
(
'persona'
)(
scope
.
user
,
'username'
)
scope
.
provider
=
$filter
(
'persona'
)(
scope
.
user
,
'provider'
)
scope
.
uclick
=
(
event
)
->
event
.
preventDefault
()
$window
.
open
"/u/
#{
scope
.
uname
}
@
#{
scope
.
provider
}
"
$window
.
open
"/u/
#{
scope
.
uname
}
"
return
scope
:
...
...
@@ -439,6 +438,20 @@ visualSearch = ['$parse', ($parse) ->
restrict
:
'C'
]
simpleSearch
=
[
'$parse'
,
(
$parse
)
->
link
:
(
scope
,
elem
,
attr
,
ctrl
)
->
scope
.
dosearch
=
->
#_search(scope.generateSearchResults())
scope
.
search
.
update
(
scope
.
searchtext
)
scope
.
$watch
attr
.
query
,
(
query
)
->
scope
.
searchtext
=
query
scope
.
search
.
update
(
scope
.
searchtext
)
restrict
:
'C'
template
:
'<form name="searchBox" ng-submit="dosearch()"><input type="text" ng-model="searchtext" name="searchText" style="width: 20em"></form>'
]
whenscrolled
=
[
'$window'
,
(
$window
)
->
link
:
(
scope
,
elem
,
attr
)
->
$window
=
angular
.
element
(
$window
)
...
...
@@ -463,4 +476,5 @@ angular.module('h.directives', ['ngSanitize'])
.
directive
(
'userPicker'
,
userPicker
)
.
directive
(
'repeatAnim'
,
repeatAnim
)
.
directive
(
'visualSearch'
,
visualSearch
)
.
directive
(
'simpleSearch'
,
simpleSearch
)
.
directive
(
'whenscrolled'
,
whenscrolled
)
h/static/scripts/displayer.coffee
View file @
9d6fb43f
...
...
@@ -4,7 +4,7 @@ imports = [
'h.directives'
'h.helpers'
'h.socket'
'h.s
treamfilter
'
'h.s
earchfilters
'
]
...
...
h/static/scripts/s
treamfilter
.coffee
→
h/static/scripts/s
earchfilters
.coffee
View file @
9d6fb43f
#ToDo: write me
# This class will parse the search filter and produce a faceted search filter object
class
SearchFilter
# This function will slice the searchtext
# Slice character: space,
# but an expression between quotes (' or ") is considered one
_tokenize
:
(
searchtext
)
->
return
[]
unless
searchtext
tokens
=
searchtext
.
match
/(?:[^\s"']+|"[^"]*"|'[^']*')+/g
# Cut the opening and closing quote characters
for
token
,
index
in
tokens
start
=
token
.
slice
0
,
1
end
=
token
.
slice
-
1
if
(
start
is
'"'
or
start
is
"'"
)
and
(
start
is
end
)
tokens
[
index
]
=
token
.
slice
1
,
token
.
length
-
1
tokens
generateFacetedFilter
:
(
searchtext
)
->
return
unless
searchtext
terms
=
@
_tokenize
(
searchtext
)
any
=
[]
quote
=
[]
result
=
[]
since
=
[]
tag
=
[]
text
=
[]
uri
=
[]
user
=
[]
for
term
in
terms
filter
=
term
.
slice
0
,
term
.
indexOf
":"
unless
filter
?
then
filter
=
""
switch
filter
when
'quote'
then
quote
.
push
term
[
6
..]
when
'result'
then
result
.
push
term
[
7
..]
when
'since'
# We'll turn this into seconds
time
=
term
[
6
..].
toLowerCase
()
if
time
.
match
/^\d+$/
# Only digits, assuming seconds
since
.
push
time
if
time
.
match
/^\d+sec$/
# Time given in seconds
t
=
/^(\d+)sec$/
.
exec
(
time
)[
1
]
since
.
push
t
if
time
.
match
/^\d+min$/
# Time given in minutes
t
=
/^(\d+)min$/
.
exec
(
time
)[
1
]
since
.
push
t
*
60
if
time
.
match
/^\d+hour$/
# Time given in hours
t
=
/^(\d+)hour$/
.
exec
(
time
)[
1
]
since
.
push
t
*
60
*
60
if
time
.
match
/^\d+day$/
# Time given in days
t
=
/^(\d+)day$/
.
exec
(
time
)[
1
]
since
.
push
t
*
60
*
60
*
24
if
time
.
match
/^\d+week$/
# Time given in week
t
=
/^(\d+)week$/
.
exec
(
time
)[
1
]
since
.
push
t
*
60
*
60
*
24
*
7
if
time
.
match
/^\d+month$/
# Time given in month
t
=
/^(\d+)month$/
.
exec
(
time
)[
1
]
since
.
push
t
*
60
*
60
*
24
*
30
if
time
.
match
/^\d+year$/
# Time given in year
t
=
/^(\d+)year$/
.
exec
(
time
)[
1
]
since
.
push
t
*
60
*
60
*
24
*
365
when
'tag'
then
tag
.
push
term
[
4
..]
when
'text'
then
text
.
push
term
[
5
..]
when
'uri'
then
uri
.
push
term
[
4
..]
when
'user'
then
user
.
push
term
[
5
..]
else
any
.
push
term
any
:
terms
:
any
operator
:
'and'
lowercase
:
true
quote
:
terms
:
quote
operator
:
'lower'
lowercase
:
true
result
:
terms
:
result
operator
:
'min'
lowercase
:
false
since
:
terms
:
since
operator
:
'min'
lowercase
:
false
tag
:
terms
:
tag
operator
:
'and'
lowercase
:
true
text
:
terms
:
text
operator
:
'and'
lowercase
:
true
uri
:
terms
:
uri
operator
:
'or'
lowercase
:
true
user
:
terms
:
user
operator
:
'or'
lowercase
:
true
# This class will process the results of search and generate the correct filter
# It expects the following dict format as rules
# { facet_name : {
...
...
@@ -220,6 +332,7 @@ class StreamFilter
this
angular
.
module
(
'h.streamfilter'
,
[])
angular
.
module
(
'h.searchfilters'
,
[])
.
service
(
'searchfilter'
,
SearchFilter
)
.
service
(
'queryparser'
,
QueryParser
)
.
service
(
'streamfilter'
,
StreamFilter
)
h/static/scripts/services.coffee
View file @
9d6fb43f
imports
=
[
'h.filters'
'h.filters'
,
'h.searchfilters'
]
...
...
@@ -674,18 +675,105 @@ class DraftProvider
class
ViewFilter
this
.
$inject
=
[
'$filter'
]
constructor
:
(
$filter
)
->
checkers
:
quote
:
autofalse
:
(
annotation
)
->
return
annotation
.
references
?
value
:
(
annotation
)
->
for
target
in
annotation
.
target
return
target
.
quote
if
target
.
quote
?
''
match
:
(
term
,
value
)
->
return
value
.
indexOf
(
term
)
>
-
1
since
:
autofalse
:
(
annotation
)
->
return
not
annotation
.
updated
?
value
:
(
annotation
)
->
return
annotation
.
updated
match
:
(
term
,
value
)
->
delta
=
Math
.
round
((
+
new
Date
-
new
Date
(
value
))
/
1000
)
return
delta
<=
term
tag
:
autofalse
:
(
annotation
)
->
return
not
annotation
.
tags
?
value
:
(
annotation
)
->
return
annotation
.
tags
match
:
(
term
,
value
)
->
return
value
in
term
text
:
autofalse
:
(
annotation
)
->
return
not
annotation
.
text
?
value
:
(
annotation
)
->
return
annotation
.
text
match
:
(
term
,
value
)
->
return
value
.
indexOf
(
term
)
>
-
1
uri
:
autofalse
:
(
annotation
)
->
return
not
annotation
.
uri
?
value
:
(
annotation
)
->
return
annotation
.
uri
match
:
(
term
,
value
)
->
return
value
is
term
user
:
autofalse
:
(
annotation
)
->
return
not
annotation
.
user
?
value
:
(
annotation
)
->
# XXX: Hopefully there is a cleaner solution
# XXX: To reach persona filter from here
return
(
annotation
.
user
?
.
match
/^acct:([^@]+)@(.+)/
)
?
[
1
]
match
:
(
term
,
value
)
->
return
value
is
term
any
:
fields
:
[
'quote'
,
'text'
,
'tag'
,
'user'
]
this
.
$inject
=
[
'$filter'
,
'searchfilter'
]
constructor
:
(
$filter
,
searchfilter
)
->
@
user_filter
=
$filter
(
'persona'
)
@
searchfilter
=
searchfilter
_matches
:
(
filter
,
value
,
match
)
->
matches
=
true
for
term
in
filter
.
terms
unless
match
term
,
value
matches
=
false
if
filter
.
operator
is
'and'
break
else
matches
=
true
if
filter
.
operator
is
'or'
break
matches
_arrayMatches
:
(
filter
,
value
,
match
)
->
matches
=
true
# Make copy for filtering
copy
=
value
.
slice
()
copy
.
filter
(
e
)
->
not
match
filter
.
terms
,
e
if
(
filter
.
operator
is
'and'
and
copy
.
length
<
value
.
length
)
or
(
filter
.
operator
is
'or'
and
not
copy
.
length
)
matches
=
false
matches
_anyMatches
:
(
filter
,
value
,
match
)
->
matchresult
=
[]
for
term
in
filter
.
terms
if
value
instanceof
Array
matchresult
.
push
match
value
,
term
else
matchresult
.
push
match
term
,
value
matchresult
_checkMatch
:
(
filter
,
annotation
,
checker
)
->
autofalsefn
=
checker
.
autofalse
return
false
if
autofalsefn
?
and
autofalsefn
annotation
value
=
checker
.
value
annotation
if
value
instanceof
Array
if
filter
.
lowercase
then
value
=
value
.
map
(
e
)
->
e
.
toLowerCase
()
return
@
_arrayMatches
filter
,
value
,
checker
.
match
else
value
=
value
.
toLowerCase
()
if
filter
.
lowercase
return
@
_matches
filter
,
value
,
checker
.
match
# Filters a set of annotations, according to a given query.
#
# annotations is the input list of annotations (array)
# ToDo: update me I'm not up to date!
# query is the query; it's a map. Supported key values are:
# user: username to search for
# text: text to search for in the body (all the words must be present)
# quote: text to search for in the quote (exact phr
e
ase must be present)
# quote: text to search for in the quote (exact phrase must be present)
# tags: list of tags to search for. (all must be present)
# time: maximum age of annotation. Accepted values:
# '5 min', '30 min', '1 hour', '12 hours',
...
...
@@ -694,16 +782,22 @@ class ViewFilter
# All search is case insensitive.
#
# Returns the list of matching annotation IDs.
filter
:
(
annotations
,
query
)
->
filter
:
(
annotations
,
query
)
=>
return
[]
unless
query
.
query
filters
=
@
searchfilter
.
generateFacetedFilter
query
.
query
results
=
[]
# Convert these fields to lower case, if they exist
for
key
in
[
'text'
,
'user'
]
if
query
[
key
]
?
query
[
key
]
=
query
[
key
].
toLowerCase
()
# Check for given limit
# Find the minimal
limit
=
0
if
filters
.
result
.
terms
.
length
limit
=
filter
.
result
.
terms
[
0
]
for
term
in
filter
.
result
.
terms
if
limit
>
term
then
limit
=
term
# We expect a list for quotes
query
.
quote
.
map
(
e
)
->
e
.
toLowerCase
()
# Convert terms to lowercase if needed
for
_
,
filter
of
filters
if
filter
.
lowercase
then
filter
.
terms
.
map
(
e
)
->
e
.
toLowerCase
()
# Now that this filter is called with the top level annotations, we have to add the children too
annotationsWithChildren
=
[]
...
...
@@ -716,104 +810,55 @@ class ViewFilter
for
annotation
in
annotationsWithChildren
matches
=
true
for
category
,
value
of
query
#ToDo: What about given zero limit?
# Limit reached
if
limit
and
results
.
length
>=
limit
then
break
for
category
,
filter
of
filters
continue
if
category
is
'timestamp'
break
unless
matches
terms
=
filter
.
terms
# No condition for this category
continue
unless
terms
.
length
switch
category
when
'user'
username
=
@
user_filter
annotation
.
user
unless
username
?
.
toLowerCase
()
is
value
matches
=
false
break
when
'text'
unless
annotation
.
text
?
matches
=
false
break
lowerCaseText
=
annotation
.
text
.
toLowerCase
()
for
token
in
value
.
split
' '
if
lowerCaseText
.
indexOf
(
token
)
is
-
1
matches
=
false
break
when
'quote'
unless
value
.
length
>
0
then
continue
# Reply annotations does not have a quote in this aspect
if
annotation
.
references
?
matches
=
false
break
when
'result'
# Handled above
continue
when
'any'
# Special case
matchterms
=
[]
matchterms
.
push
false
for
term
in
terms
for
field
in
@
checkers
.
any
.
fields
conf
=
@
checkers
[
field
]
continue
if
conf
.
autofalse
?
and
conf
.
autofalse
annotation
value
=
conf
.
value
annotation
if
value
instanceof
Array
if
filter
.
lowercase
value
=
value
.
map
(
e
)
->
e
.
toLowerCase
()
else
value
=
value
.
toLowerCase
()
if
filter
.
lowercase
matchresult
=
@
_anyMatches
filter
,
value
,
conf
.
match
matchterms
=
matchterms
.
map
(
t
,
i
)
->
t
or
matchresult
[
i
]
# Now let's see what we got.
matched
=
0
for
_
,
value
of
matchterms
matched
++
if
value
if
(
filter
.
operator
is
'or'
and
matched
>
0
)
or
(
filter
.
operator
is
'and'
and
matched
is
terms
.
length
)
matches
=
true
else
found
=
false
for
target
in
annotation
.
target
if
target
.
quote
?
quote
=
target
.
quote
.
toLowerCase
()
for
val
in
value
if
quote
.
indexOf
(
val
)
>
-
1
found
=
true
else
found
=
false
break
unless
found
matches
=
false
break
when
'tags'
# Don't bother if we got an empty list for required tags
break
unless
value
.
length
# If this has no tags, this is in instant failure
if
value
.
length
and
not
annotation
.
tags
?
matches
=
false
break
# OK, there are some tags, and we need some tags.
# Gotta check for each wanted tag
for
wantedTag
in
value
found
=
false
for
existingTag
in
annotation
.
tags
if
existingTag
.
toLowerCase
().
indexOf
(
wantedTag
)
>
-
1
found
=
true
break
unless
found
matches
=
false
break
when
'time'
delta
=
Math
.
round
((
+
new
Date
-
new
Date
(
annotation
.
updated
))
/
1000
)
switch
value
when
'5 min'
unless
delta
<=
60
*
5
matches
=
false
when
'30 min'
unless
delta
<=
60
*
30
matches
=
false
when
'1 hour'
unless
delta
<=
60
*
60
matches
=
false
when
'12 hours'
unless
delta
<=
60
*
60
*
12
matches
=
false
when
'1 day'
unless
delta
<=
60
*
60
*
24
matches
=
false
when
'1 week'
unless
delta
<=
60
*
60
*
24
*
7
matches
=
false
when
'1 month'
unless
delta
<=
60
*
60
*
24
*
31
matches
=
false
when
'1 year'
unless
delta
<=
60
*
60
*
24
*
366
matches
=
false
when
'group'
priv_public
=
'group:__world__'
in
(
annotation
.
permissions
.
read
or
[])
switch
value
when
'Public'
unless
priv_public
matches
=
false
when
'Private'
if
priv_public
matches
=
false
matches
=
false
else
# For all other categories
matches
=
@
_checkMatch
filter
,
annotation
,
@
checkers
[
category
]
if
matches
results
.
push
annotation
.
id
results
[
results
,
filters
]
angular
.
module
(
'h.services'
,
imports
)
...
...
h/static/scripts/streamsearch.coffee
View file @
9d6fb43f
...
...
@@ -6,7 +6,7 @@ imports = [
'h.flash'
'h.helpers'
'h.session'
'h.s
treamfilter
'
'h.s
earchfilters
'
]
SEARCH_FACETS
=
[
'text'
,
'tags'
,
'uri'
,
'quote'
,
'since'
,
'user'
,
'results'
]
...
...
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