Commit 0125ec0e authored by Randall Leeds's avatar Randall Leeds

Merge branch 'user-stream-4' into develop

parents ccde211b 4be1b200
......@@ -977,6 +977,20 @@ pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
overflow-y:hidden;
}
.annotation-header-border {
padding: 0.5em;
overflow: hidden;
}
.annotation-header-width {
padding: 0.2em;
overflow: hidden;
}
.annotation-header-favicon {
width: 1em;
vertical-align: middle;
}
.searchbar {
margin-top: 8em;
......
......@@ -260,6 +260,35 @@ ngBlur = ['$parse', ($parse) ->
$event: event
]
repeatAnim = ->
restrict: 'A'
scope:
array: '='
template: '<div ng-init="runAnimOnLast()"><div ng-transclude></div></div>'
transclude: true
controller: ($scope, $element, $attrs) ->
$scope.runAnimOnLast = ->
#Run anim on the item's element
#(which will be last child of directive element)
item=$scope.array[0]
itemElm = jQuery($element)
.children()
.first()
.children()
unless item._anim?
return
if item._anim is 'fade'
itemElm
.css({ opacity: 0 })
.animate({ opacity: 1 }, 1500)
else
if item._anim is 'slide'
itemElm
.css({ 'margin-left': itemElm.width() })
.animate({ 'margin-left': '0px' }, 1500)
angular.module('h.directives', ['ngSanitize'])
.directive('annotation', annotation)
.directive('authentication', authentication)
......@@ -272,4 +301,5 @@ angular.module('h.directives', ['ngSanitize'])
.directive('thread', thread)
.directive('userPicker', userPicker)
.directive('ngBlur', ngBlur)
.directive('repeatAnim', repeatAnim)
......@@ -9,10 +9,12 @@ get_quote = (annotation) ->
quote
class Displayer
this.$inject = ['$scope','$element','$timeout']
path: window.location.protocol + '//' + window.location.hostname + ':' +
window.location.port + '/__streamer__'
idTable : {}
constructor: ($scope, $element, $timeout) ->
this.$inject = ['$scope','$element','$timeout','streamfilter']
constructor: ($scope, $element, $timeout, streamfilter) ->
$scope.annotation = {}
$scope.annotations = [$scope.annotation]
$scope.annotation.replies = []
......@@ -20,22 +22,12 @@ class Displayer
$scope.annotation.id = document.body.attributes.internalid.value
@idTable[$scope.annotation.id] = $scope.annotation
$scope.filter =
match_policy : 'include_any'
clauses : [
field: "/references"
operator: "first_of"
value: $scope.annotation.id
,
field: "/id"
operator: "equals"
value: $scope.annotation.id
]
actions :
create: true
edit: true
delete: true
past_data:
load_past: "none"
streamfilter
.setPastDataNone()
.setMatchPolicyIncludeAny()
.addClausesParse('references:^' + $scope.annotation.id)
.addClausesParse('id:=' + $scope.annotation.id)
.getFilter()
$scope.change_annotation_content = (id, new_annotation) =>
to_change = @idTable[id]
......@@ -48,13 +40,12 @@ class Displayer
to_change.reply_count = reply_count
$scope.open = =>
transports = ['xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling']
$scope.sock = new SockJS(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/__streamer__', transports)
$scope.sock = new SockJS @path
$scope.sock.onopen = ->
$scope.sock.onopen = =>
$scope.sock.send JSON.stringify $scope.filter
$scope.sock.onclose = ->
$scope.sock.onclose = =>
$timeout $scope.open, 5000
$scope.sock.onmessage = (msg) =>
......@@ -63,6 +54,7 @@ class Displayer
data = msg.data[0]
action = msg.data[1]
unless data instanceof Array then data = [data]
$scope.$apply =>
$scope.manage_new_data data, action
......@@ -127,5 +119,5 @@ class Displayer
document.initial_replies = ''
$scope.open()
angular.module('h.displayer',['h.filters','bootstrap'])
angular.module('h.displayer',['h.streamfilter','h.filters','bootstrap'])
.controller('DisplayerCtrl', Displayer)
......@@ -38,9 +38,14 @@ fuzzyTime = (date) ->
userName = (user) ->
(user?.match /^acct:([^@]+)/)?[1]
elide = (text, split_length) ->
if text.length > split_length
text = text.substring 0,split_length
text = text + '\u2026'
text
angular.module('h.filters', [])
.filter('converter', -> (new Converter()).makeHtml)
.filter('fuzzyTime', -> fuzzyTime)
.filter('userName', -> userName)
\ No newline at end of file
.filter('elide', -> elide)
......@@ -22,89 +22,23 @@ syntaxHighlight = (json) ->
return '<span class="' + cls + '">' + match + '</span>'
)
class ClauseParser
filter_fields : ['references', 'text', 'user','uri', 'id']
operators: ['=', '>', '<', '=>', '>=', '<=', '=<', '[', '#']
operator_mapping:
'=': 'equals'
'>': 'gt'
'<': 'lt'
'=>' : 'ge'
'<=' : 'ge'
'=<': 'le'
'<=' : 'le'
'[' : 'one_of'
'#' : 'matches'
parse_clauses: (clauses) ->
bads = []
structure = []
unless clauses
return
clauses = clauses.split ' '
for clause in clauses
#Here comes the long and boring validation checking
clause = clause.trim()
if clause.length < 1 then continue
parts = clause.split /:(.+)/
unless parts.length > 1
bads.push [clause, 'Filter clause is not well separated']
continue
unless parts[0] in @filter_fields
bads.push [clause, 'Unknown filter field']
continue
field = parts[0]
operator_found = false
for operator in @operators
if (parts[1].indexOf operator) is 0
oper = @operator_mapping[operator]
if operator is '['
value = parts[1][operator.length..].split ','
else
value = parts[1][operator.length..]
operator_found = true
break
unless operator_found
bads.push [clause, 'Unknown operator']
continue
structure.push
'field' : '/' + field
'operator': oper
'value' : value
[structure, bads]
class Streamer
path: window.location.protocol + '//' + window.location.hostname + ':' +
window.location.port + '/__streamer__'
strategies: ['include_any', 'include_all', 'exclude_any', 'exclude_all']
past_modes: ['none','hits','time']
this.$inject = ['$location', '$scope']
constructor: ($location, $scope) ->
this.$inject = ['$location', '$scope', 'streamfilter', 'clauseparser']
constructor: ($location, $scope, streamfilter, clauseparser) ->
$scope.streaming = false
$scope.annotations = []
$scope.bads = []
$scope.time = 5
$scope.hits = 100
@parser = new ClauseParser()
#Json structure we will watch and update
$scope.filter =
match_policy : 'include_any'
clauses : []
actions :
create: true
edit: true
delete: true
past_data:
load_past: 'hits'
go_back: 5
hits: 100
@sfilter = streamfilter
@sfilter.setPastDataHits(100)
$scope.filter = @sfilter.filter
#parse for route params
params = $location.search()
......@@ -113,43 +47,40 @@ class Streamer
if params.action_create
if (typeof params.action_create) is 'boolean'
$scope.filter.actions.create = params.action_create
@sfilter.setActionCreate(params.action_create)
else
$scope.filter.actions.create = params.action_create is 'true'
@sfilter.setActionCreate(params.action_create is 'true')
if params.action_edit
if (typeof params.action_edit) is 'boolean'
$scope.filter.actions.edit = params.action_edit
@sfilter.setActionEdit(params.action_edit)
else
$scope.filter.actions.edit = params.action_edit is 'true'
@sfilter.setActionEdit(params.action_edit is 'true')
if params.action_delete
if (typeof params.action_delete) is 'boolean'
$scope.filter.actions.delete = params.action_delete
@sfilter.setActionDelete(params.action_delete)
else
$scope.filter.actions.delete = params.action_delete is 'true'
@sfilter.setActionDelete(params.action_delete is 'true')
if params.load_past in @past_modes
$scope.filter.past_data.load_past = params.load_past
if params.hits? and parseInt(params.hits) is not NaN
$scope.filter.past_data.hits = parseInt(params.hits)
if params.go_back? and parseInt(params.go_back) is not NaN
$scope.filter.past_data.go_back = parseInt(params.go_back)
if params.hits? and parseInt(params.hits) is not NaN
@sfilter.setPastDataHits(parseInt(params.hits))
if params.go_back? and parseInt(params.go_back) is not NaN
@sfilter.setPastDataTime(parseInt(params.go_back))
if params.clauses
test_clauses = params.clauses.replace ",", " "
res = @parser.parse_clauses test_clauses
if res[1]?.length is 0
$scope.filter.clauses = res[0]
$scope.clauses = test_clauses
@sfilter.setClausesParse(test_clauses)
$scope.clauses = test_clauses
else
$scope.clauses = ""
$scope.clauses = ''
console.log $scope.filter
$scope.toggle_past = ->
switch $scope.filter.past_data.load_past
when 'none' then $scope.filter.past_data.load_past = 'time'
when 'time' then $scope.filter.past_data.load_past = 'hits'
when 'hits' then $scope.filter.past_data.load_past = 'none'
when 'none' then @sfilter.setPastDataTime($scope.time)
when 'time' then @sfilter.setPastDataHits($scope.hits)
when 'hits' then @sfilter.setPastDataNone()
$scope.$watch 'filter', (newValue, oldValue) =>
json = JSON.stringify $scope.filter, undefined, 2
......@@ -158,7 +89,7 @@ class Streamer
$scope.clause_change = =>
if $scope.clauses.slice(-1) is ' ' or $scope.clauses.length is 0
res = @parser.parse_clauses($scope.clauses)
res = clauseparser.parse_clauses($scope.clauses)
if res?
$scope.filter.clauses = res[0]
$scope.bads = res[1]
......@@ -171,34 +102,39 @@ class Streamer
$scope.sock.close()
$scope.streaming = false
res = @parser.parse_clauses($scope.clauses)
res = clauseparser.parse_clauses($scope.clauses)
if res
$scope.filter.clauses = res[0]
$scope.bads = res[1]
unless $scope.bads.length is 0
return
$scope.open()
transports = ['xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling']
$scope.sock = new SockJS(window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/__streamer__', transports)
$scope.open = =>
$scope.sock = new SockJS @path
$scope.sock.onopen = ->
$scope.sock.send (JSON.stringify $scope.filter)
$scope.$apply =>
$scope.streaming = true
$scope.sock.onopen = =>
$scope.sock.send JSON.stringify $scope.filter
$scope.streaming = true
$scope.sock.onclose = ->
$scope.$apply =>
$scope.streaming = false
$scope.sock.onclose = =>
$scope.streaming = false
$scope.sock.onmessage = (msg) =>
console.log 'Got something'
console.log msg
data = msg.data[0]
action = msg.data[1]
unless data instanceof Array then data = [data]
$scope.$apply =>
data = msg.data[0]
unless data instanceof Array then data = [data]
action = msg.data[1]
for annotation in data
annotation['action'] = action
annotation['quote'] = get_quote annotation
$scope.annotations.splice 0,0,annotation
$scope.manage_new_data data, action
$scope.manage_new_data = (data, action) =>
for annotation in data
annotation.action = action
annotation.quote = get_quote annotation
$scope.annotations.splice 0,0,annotation
#Update the parameters
$location.search
......@@ -215,7 +151,7 @@ class Streamer
$scope.sock.close()
$scope.streaming = false
angular.module('h.streamer',['h.filters','bootstrap'])
angular.module('h.streamer',['h.streamfilter','h.filters','bootstrap'])
.controller('StreamerCtrl', Streamer)
class ClauseParser
filter_fields : ['references', 'text', 'user','uri', 'id']
operators: ['=', '>', '<', '=>', '>=', '<=', '=<', '[', '#', '^']
operator_mapping:
'=': 'equals'
'>': 'gt'
'<': 'lt'
'=>' : 'ge'
'<=' : 'ge'
'=<': 'le'
'<=' : 'le'
'[' : 'one_of'
'#' : 'matches'
'^' : 'first_of'
parse_clauses: (clauses) ->
bads = []
structure = []
unless clauses
return
clauses = clauses.split ' '
for clause in clauses
#Here comes the long and boring validation checking
clause = clause.trim()
if clause.length < 1 then continue
parts = clause.split /:(.+)/
unless parts.length > 1
bads.push [clause, 'Filter clause is not well separated']
continue
unless parts[0] in @filter_fields
bads.push [clause, 'Unknown filter field']
continue
field = parts[0]
operator_found = false
for operator in @operators
if (parts[1].indexOf operator) is 0
oper = @operator_mapping[operator]
if operator is '['
value = parts[1][operator.length..].split ','
else
value = parts[1][operator.length..]
operator_found = true
if field is 'user'
value = 'acct:' + value + '@' + window.location.hostname + ':' + window.location.port
break
unless operator_found
bads.push [clause, 'Unknown operator']
continue
structure.push
'field' : '/' + field
'operator': oper
'value' : value
[structure, bads]
class StreamFilter
strategies: ['include_any', 'include_all', 'exclude_any', 'exclude_all']
past_modes: ['none','hits','time']
filter:
match_policy : 'include_any'
clauses : []
actions :
create: true
edit: true
delete: true
past_data:
load_past: "none"
constructor: ->
@parser = new ClauseParser()
getFilter: -> return @filter
getPastData: -> return @filter.past_data
getMatchPolicy: -> return @filter.match_policy
getClauses: -> return @filter.clauses
getActions: -> return @filter.actions
getActionCreate: -> return @filter.actions.create
getActionEdit: -> return @filter.actions.edit
getActionDelete: -> return @filter.actions.delete
setPastDataNone: ->
@filter.past_data =
load_past: 'none'
this
setPastDataHits: (hits) ->
@filter.past_data =
load_past: 'hits'
hits: hits
this
setPastDataTime: (time) ->
@filter.past_data =
load_past: 'hits'
go_back: time
this
setMatchPolicy: (policy) ->
@filter.match_policy = policy
this
setMatchPolicyIncludeAny: ->
@filter.match_policy = 'include_any'
this
setMatchPolicyIncludeAll: ->
@filter.match_policy = 'include_all'
this
setMatchPolicyExcludeAny: ->
@filter.match_policy = 'exclude_any'
this
setMatchPolicyExcludeAll: ->
@filter.match_policy = 'exclude_all'
this
setActions: (actions) ->
@filter.actions = actions
this
setActionCreate: (action) ->
@filter.actions.create = action
this
setActionEdit: (action) ->
@filter.actions.edit = action
this
setActionDelete: (action) ->
@filter.actions.delete = action
this
noClauses: ->
@filter.clauses = []
this
addClause: (clause) ->
@filter.clauses.push clause
this
addClause: (field, operator, value) ->
@filter.clauses.push
field: field
operator: operator
value: value
this
setClausesParse: (clauses_to_parse, error_checking = false) ->
res = @parser.parse_clauses clauses_to_parse
if res? and (not error_checking) or (error_checking and res[1]?.length is 0)
@filter.clauses = res[0]
this
addClausesParse: (clauses_to_parse, error_checking = false) ->
res = @parser.parse_clauses clauses_to_parse
if res? and (not error_checking) or (error_checking and res[1]?.length is 0)
for clause in res[0]
@filter.clauses.push clause
this
resetFilter: ->
@setMatchPolicyIncludeAny()
@setActionCreate(true)
@setActionEdit(true)
@setActionDelete(true)
@setPastDataNone()
@noClauses()
this
angular.module('h.streamfilter',['bootstrap'])
.service('clauseparser', ClauseParser)
.service('streamfilter', StreamFilter)
\ No newline at end of file
get_quote = (annotation) ->
if not 'target' in annotation then return ''
quote = '(Reply annotation)'
for target in annotation['target']
for selector in target['selector']
if selector['type'] is 'TextQuoteSelector'
quote = selector['exact'] + ' '
quote
class UserStream
path: window.location.protocol + '//' + window.location.hostname + ':' +
window.location.port + '/__streamer__'
this.$inject = ['$location','$scope','$timeout','streamfilter']
constructor: ($location, $scope, $timeout, streamfilter) ->
$scope.annotations = []
$scope.username = $location.absUrl().split('/').pop()
$scope.filter =
streamfilter
.setPastDataHits(100)
.setMatchPolicyIncludeAny()
.setClausesParse('user:=' + $scope.username)
.getFilter()
$scope.manage_new_data = (data, action) =>
for annotation in data
annotation.action = action
annotation.quote = get_quote annotation
annotation._anim = 'fade'
$scope.annotations.splice 0,0,annotation
$scope.open = =>
$scope.sock = new SockJS(@path)
$scope.sock.onopen = =>
$scope.sock.send JSON.stringify $scope.filter
$scope.sock.onclose = =>
$timeout $scope.open, 5000
$scope.sock.onmessage = (msg) =>
console.log 'Got something'
console.log msg
data = msg.data[0]
action = msg.data[1]
unless data instanceof Array then data = [data]
$scope.$apply =>
$scope.manage_new_data data, action
$scope.open()
angular.module('h.userstream',['h.streamfilter', 'h.filters','h.directives','bootstrap'])
.controller('UserStreamCtrl', UserStream)
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