Skip to content

Commit f53b4b3

Browse files
Ryan Florencecodekitchen
Ryan Florence
authored andcommitted
collapse / expand discussion entries
also: - counts in side-comment "show all [n] replies" are now accurate - moved lock/unlock into the cog menu - moved the cog menu into the toolbar test plan: 1. go to a discussion 2. click "collapse" in the toolbar - the root entries should collapse - the page should scroll to the entries 3. expand a single reply - the reply's replies should NOT be collapsed 4. click a page number - the newly rendered entries should be collapsed 5. click expand - all the root entries should expand 6. click a page link - all the entries should be expanded 7. lock and unlock should still work 8. Go to a side comment discussion - "show all [n] replies" should have an accurate count Change-Id: Ia06fad173344c549d31b7cd51d4ecc57d2e40d5f Reviewed-on: https://gerrit.instructure.com/15834 Tested-by: Jenkins <[email protected]> Reviewed-by: Jon Jensen <[email protected]> QA-Review: Cam Theriault <[email protected]>
1 parent e60af73 commit f53b4b3

18 files changed

+356
-213
lines changed

app/coffeescripts/bundles/discussion.coffee

+30-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require [
2+
'compiled/views/DiscussionTopic/EntryView'
23
'compiled/models/DiscussionFilterState'
34
'compiled/views/DiscussionTopic/DiscussionToolbarView'
45
'compiled/views/DiscussionTopic/DiscussionFilterResultsView'
@@ -11,7 +12,8 @@ require [
1112
'compiled/collections/EntryCollection'
1213
'compiled/views/DiscussionTopic/TopicView'
1314
'compiled/views/DiscussionTopic/EntriesView'
14-
], (DiscussionFilterState, DiscussionToolbarView, DiscussionFilterResultsView, MarkAsReadWatcher, $, Backbone, Entry, MaterializedDiscussionTopic, SideCommentDiscussionTopic, EntryCollection, TopicView, EntriesView) ->
15+
'compiled/jquery/sticky'
16+
], (EntryView, DiscussionFilterState, DiscussionToolbarView, DiscussionFilterResultsView, MarkAsReadWatcher, $, Backbone, Entry, MaterializedDiscussionTopic, SideCommentDiscussionTopic, EntryCollection, TopicView, EntriesView) ->
1517

1618
perPage = 10
1719
descendants = 3
@@ -52,31 +54,54 @@ require [
5254
allData: data
5355
model: filterModel
5456

57+
$container = $ window
58+
$subentries = $ '#discussion_subentries'
59+
60+
61+
scrollToTop = ->
62+
$container.scrollTo $subentries, offset: -49
63+
5564
##
5665
# connect them ...
5766
data.on 'change', ->
5867
entries.reset data.get 'entries'
5968

6069
entriesView.on 'scrollAwayFromEntry', ->
61-
$window = $ window
6270
# prevent scroll to top for non-pushstate browsers when hash changes
63-
top = $window.scrollTop()
71+
top = $container.scrollTop()
6472
router.navigate '',
6573
trigger: false
6674
replace: true
67-
$window.scrollTo top
75+
$container.scrollTo top
6876

6977
filterView.on 'clickEntry', (entry) ->
7078
router.navigate "entry-#{entry.get 'id'}", yes
7179

80+
toolbarView.on 'expandAll', ->
81+
EntryView.expandRootEntries()
82+
scrollToTop()
83+
84+
toolbarView.on 'collapseAll', ->
85+
EntryView.collapseRootEntries()
86+
scrollToTop()
87+
88+
filterView.on 'render', ->
89+
scrollToTop()
90+
91+
filterView.on 'hide', ->
92+
scrollToTop()
93+
94+
filterModel.on 'reset', -> EntryView.expandRootEntries()
95+
96+
7297
##
7398
# routes
7499
router.route '*catchall', 'catchall', -> router.navigate '', yes
75100
router.route 'entry-:id', 'id', entriesView.goToEntry
76101
router.route 'page-:page', 'page', (page) ->
77102
entriesView.render page
78103
# TODO: can get a little bouncy when the page isn't as tall as the previous
79-
$(window).scrollTo '#discussion_subentries'
104+
scrollToTop()
80105
router.route '', 'root', entriesView.render
81106
initEntries = ->
82107
data.fetch success: ->
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
define ['underscore', 'jquery'], (_, $) ->
2+
3+
class Sticky
4+
5+
@instances: []
6+
7+
@initialized: false
8+
9+
@$container = $ window
10+
11+
@initialize: ->
12+
@$container.on 'scroll', _.debounce(@checkInstances, 10)
13+
@initialized = true
14+
15+
@addInstance: (instance) ->
16+
@initialize() unless @initialized
17+
@instances.push instance
18+
@checkInstances()
19+
20+
@checkInstances: =>
21+
containerTop = @$container.scrollTop()
22+
for instance in @instances
23+
if containerTop >= instance.top
24+
instance.stick() unless instance.stuck
25+
else
26+
instance.unstick() if instance.stuck
27+
null
28+
29+
constructor: (@$el) ->
30+
@top = @$el.offset().top
31+
@stuck = false
32+
@constructor.addInstance this
33+
34+
stick: ->
35+
@$el.addClass 'sticky'
36+
@stuck = true
37+
38+
unstick: ->
39+
@$el.removeClass 'sticky'
40+
@stuck = false
41+
42+
$.fn.sticky = ->
43+
@each -> new Sticky $ this
44+
45+
$ -> $('[data-sticky]').sticky()
46+
47+
Sticky
48+

app/coffeescripts/models/DiscussionFilterState.coffee

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ define ['Backbone'], ({Model}) ->
33
class DiscussionFilterState extends Model
44

55
defaults:
6-
unread: null
6+
unread: false
77
query: null
8+
collapsed: false
89

910
hasFilter: ->
1011
{unread, query} = @attributes
@@ -13,3 +14,11 @@ define ['Backbone'], ({Model}) ->
1314
else
1415
no
1516

17+
reset: ->
18+
@set
19+
unread: false
20+
query: null
21+
collapsed: false
22+
@trigger 'reset'
23+
24+

app/coffeescripts/views/DiscussionTopic/DiscussionFilterResultsView.coffee

+7-6
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,26 @@ define [
4848
@list.append view.el
4949

5050
clearModel: =>
51-
@model.set
52-
unread: false
53-
query: null
51+
@model.reset()
5452

5553
render: =>
5654
super if @collection?
55+
@trigger 'render'
5756
@$el.removeClass 'hidden'
5857

5958
renderOrTeardownResults: =>
6059
if @model.hasFilter()
6160
results = (entry for id, entry of @allData.flattened)
6261
for filter, value of @model.toJSON()
63-
results = @["#{filter}Filter"](value, results)
62+
filterFn = @["#{filter}Filter"]
63+
results = filterFn(value, results) if filterFn
6464
if results.length
6565
@resetCollection results
6666
else
6767
@renderNoResults()
68-
else
69-
@$el.addClass 'hidden' unless @model.hasFilter()
68+
else if not @model.hasFilter()
69+
@$el.addClass 'hidden'
70+
@trigger 'hide'
7071

7172
renderNoResults: ->
7273
@render()

app/coffeescripts/views/DiscussionTopic/DiscussionToolbarView.coffee

+18
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@ define [
1212
els:
1313
'#discussion-search': '$searchInput'
1414
'#onlyUnread': '$unread'
15+
'.disableWhileFiltering': '$disableWhileFiltering'
1516

1617
events:
1718
'keyup #discussion-search': 'filterBySearch'
1819
'change #onlyUnread': 'toggleUnread'
20+
'click #collapseAll': 'collapseAll'
21+
'click #expandAll': 'expandAll'
1922

2023
initialize: ->
2124
@model.on 'change', @clearInputs
@@ -30,17 +33,32 @@ define [
3033
@$searchInput.val ''
3134
@$unread.prop 'checked', false
3235
@$unread.button 'refresh'
36+
@maybeDisableFields()
3337

3438
filterBySearch: _.debounce ->
3539
value = @$searchInput.val()
3640
value = null if value is ''
3741
@model.set 'query', value
42+
@maybeDisableFields()
3843
, 250
3944

4045
toggleUnread: ->
4146
# setTimeout so the ui can update the button before the rest
4247
# do expensive stuff
48+
4349
setTimeout =>
4450
@model.set 'unread', @$unread.prop 'checked'
51+
@maybeDisableFields()
4552
, 50
4653

54+
collapseAll: ->
55+
@model.set 'collapsed', true
56+
@trigger 'collapseAll'
57+
58+
expandAll: ->
59+
@model.set 'collapsed', false
60+
@trigger 'expandAll'
61+
62+
maybeDisableFields: ->
63+
@$disableWhileFiltering.attr 'disabled', @model.hasFilter()
64+

app/coffeescripts/views/DiscussionTopic/EntriesView.coffee

+3-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ define [
1515
showMoreDescendants: 2
1616
children: 3
1717

18-
$body: $ 'body:first'
19-
2018
$window: $ window
2119

2220
initialize: ->
@@ -98,8 +96,8 @@ define [
9896
@goToEntry entryData
9997

10098
scrollToEl: ($el) ->
101-
@$body.scrollTo $el, 200,
102-
offset: -100
99+
@$window.scrollTo $el, 200,
100+
offset: -150
103101
onAfter: =>
104102
# pretty blinking
105103
setTimeout (-> $el.addClass 'highlight' ), 200
@@ -128,6 +126,7 @@ define [
128126
displayShowMore: no
129127
threaded: @options.threaded
130128
root: true
129+
collapsed: @model.get 'collapsed'
131130
@collectionView.render()
132131
@renderPageNav()
133132
this

app/coffeescripts/views/DiscussionTopic/EntryCollectionView.coffee

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ define [
1616
displayShowMore: true
1717

1818
# maybe make a sub-class for threaded discussions if the branching gets
19-
# out of control
19+
# out of control. UPDATE: it is out of control
2020
threaded: false
2121

2222
# its collection represents the root of the discussion, should probably
@@ -52,6 +52,7 @@ define [
5252
children: @collection.options.perPage
5353
showMoreDescendants: @options.showMoreDescendants
5454
threaded: @options.threaded
55+
collapsed: @options.collapsed
5556
view.render()
5657
return @addNewView view if entry.get 'new'
5758
if @options.descendants
@@ -90,7 +91,10 @@ define [
9091
@nextLink = $ '<div/>'
9192
showMore = true
9293
if not @options.threaded
93-
moreText = I18n.t('show_all_n_replies', {one: "Show one reply", other: "Show all %{count} replies"}, {count: stats.total})
94+
moreText = I18n.t 'show_all_n_replies',
95+
one: "Show one reply"
96+
other: "Show all %{count} replies"
97+
{count: stats.total + @collection.options.perPage}
9498
@nextLink.html entryStats({stats, moreText, showMore: yes})
9599
@nextLink.addClass 'showMore loadNext'
96100
if @options.threaded

app/coffeescripts/views/DiscussionTopic/EntryView.coffee

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
define [
2+
'underscore'
23
'i18n!discussions'
34
'compiled/discussions/MarkAsReadWatcher'
45
'compiled/arr/walk'
@@ -15,10 +16,21 @@ define [
1516
'compiled/str/convertApiUserContent'
1617
'jst/_avatar'
1718
'jst/discussions/_reply_form'
18-
], (I18n, MarkAsReadWatcher, walk, Backbone, EntryCollection, entryContentPartial, deletedEntriesTemplate, entryWithRepliesTemplate, entryStats, Reply, EntryEditor, htmlEscape, {publish}, convertApiUserContent) ->
19+
], (_, I18n, MarkAsReadWatcher, walk, Backbone, EntryCollection, entryContentPartial, deletedEntriesTemplate, entryWithRepliesTemplate, entryStats, Reply, EntryEditor, htmlEscape, {publish}, convertApiUserContent) ->
1920

2021
class EntryView extends Backbone.View
2122

23+
@instances = {}
24+
25+
@collapseRootEntries = ->
26+
_.each @instances, (view) ->
27+
view.collapse() unless view.model.get 'parent'
28+
29+
@expandRootEntries = ->
30+
_.each @instances, (view) ->
31+
view.expand() unless view.model.get 'parent'
32+
33+
2234
els:
2335
'.discussion_entry:first': '$entryContent'
2436
'.replies:first': '$replies'
@@ -42,6 +54,7 @@ define [
4254

4355
initialize: ->
4456
super
57+
@constructor.instances[@cid] = this
4558
@$el.attr 'id', "entry-#{@model.get 'id'}"
4659
@model.on 'change:deleted', @toggleDeleted
4760
@model.on 'change:read_state', @toggleReadState
@@ -75,6 +88,13 @@ define [
7588
@addCountsToHeader() unless @addedCountsToHeader
7689
@$el.toggleClass 'collapsed'
7790

91+
expand: ->
92+
@$el.removeClass 'collapsed'
93+
94+
collapse: ->
95+
@addCountsToHeader() unless @addedCountsToHeader
96+
@$el.addClass 'collapsed'
97+
7898
addCountsToHeader: ->
7999
stats = @countPosterity()
80100
html = """
@@ -91,6 +111,7 @@ define [
91111

92112
afterRender: ->
93113
super
114+
@collapse() if @options.collapsed
94115
if @model.get('read_state') is 'unread'
95116
@readMarker ?= new MarkAsReadWatcher this
96117
# this is throttled so calling it here is okay

0 commit comments

Comments
 (0)