Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
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
edx
edx-platform
Commits
57fa123f
Commit
57fa123f
authored
Nov 15, 2016
by
alisan617
Committed by
GitHub
Nov 15, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Revert PR#13843"
parent
e5a57e75
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
664 additions
and
704 deletions
+664
-704
common/static/common/js/discussion/views/discussion_thread_list_view.js
+30
-309
common/static/common/js/spec/discussion/view/discussion_thread_edit_view_spec.js
+1
-1
common/static/common/js/spec/discussion/view/discussion_thread_list_view_spec.js
+82
-223
common/static/common/js/spec/discussion/view/discussion_thread_show_view_spec.js
+1
-1
common/static/common/js/spec/discussion/view/discussion_thread_view_spec.js
+5
-5
common/static/common/js/spec/discussion/view/response_comment_view_spec.js
+1
-1
common/static/common/js/spec_helpers/discussion_spec_helper.js
+21
-8
common/test/acceptance/tests/discussion/test_discussion.py
+2
-0
lms/djangoapps/discussion/static/discussion/js/discussion_board_factory.js
+31
-51
lms/djangoapps/discussion/static/discussion/js/discussion_profile_page_factory.js
+13
-4
lms/djangoapps/discussion/static/discussion/js/discussion_router.js
+25
-22
lms/djangoapps/discussion/static/discussion/js/spec/discussion_board_factory_spec.js
+28
-11
lms/djangoapps/discussion/static/discussion/js/spec/discussion_board_view_spec.js
+58
-0
lms/djangoapps/discussion/static/discussion/js/spec/views/discussion_search_view_spec.js
+0
-36
lms/djangoapps/discussion/static/discussion/js/views/discussion_board_view.js
+336
-0
lms/djangoapps/discussion/static/discussion/js/views/discussion_search_view.js
+1
-18
lms/djangoapps/discussion/static/discussion/templates/discussion-home.underscore
+0
-0
lms/djangoapps/discussion/templates/discussion/discussion_board.html
+2
-0
lms/static/lms/js/spec/main.js
+22
-11
lms/templates/discussion/_js_body_dependencies.html
+3
-0
lms/templates/discussion/_thread_list_template.html
+1
-2
lms/templates/discussion/_underscore_templates.html
+1
-1
No files found.
common/static/common/js/discussion/views/discussion_thread_list_view.js
View file @
57fa123f
/* globals _, Backbone, Content, Discussion, DiscussionUtil */
/* globals _, Backbone, Content, Discussion, DiscussionUtil
, DiscussionThreadView, DiscussionThreadListView
*/
(
function
()
{
'use strict'
;
/* eslint-disable */
var
__hasProp
=
{}.
hasOwnProperty
,
__extends
=
function
(
child
,
parent
)
{
for
(
var
key
in
parent
)
{
...
...
@@ -17,6 +18,7 @@
child
.
__super__
=
parent
.
prototype
;
return
child
;
};
/* eslint-enable */
if
(
typeof
Backbone
!==
'undefined'
&&
Backbone
!==
null
)
{
this
.
DiscussionThreadListView
=
(
function
(
_super
)
{
...
...
@@ -36,24 +38,6 @@
this
.
chooseFilter
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
chooseFilter
.
apply
(
self
,
arguments
);
};
this
.
keyboardBinding
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
keyboardBinding
.
apply
(
self
,
arguments
);
};
this
.
filterTopics
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
filterTopics
.
apply
(
self
,
arguments
);
};
this
.
toggleBrowseMenu
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
toggleBrowseMenu
.
apply
(
self
,
arguments
);
};
this
.
hideBrowseMenu
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
hideBrowseMenu
.
apply
(
self
,
arguments
);
};
this
.
showBrowseMenu
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
showBrowseMenu
.
apply
(
self
,
arguments
);
};
this
.
isBrowseMenuVisible
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
isBrowseMenuVisible
.
apply
(
self
,
arguments
);
};
this
.
threadRemoved
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
threadRemoved
.
apply
(
self
,
arguments
);
};
...
...
@@ -72,9 +56,6 @@
this
.
renderThreads
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
renderThreads
.
apply
(
self
,
arguments
);
};
this
.
updateSidebar
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
updateSidebar
.
apply
(
self
,
arguments
);
};
this
.
addAndSelectThread
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
addAndSelectThread
.
apply
(
self
,
arguments
);
};
...
...
@@ -90,17 +71,16 @@
this
.
addSearchAlert
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
addSearchAlert
.
apply
(
self
,
arguments
);
};
return
DiscussionThreadListView
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
this
.
performSearch
=
function
()
{
return
DiscussionThreadListView
.
prototype
.
performSearch
.
apply
(
self
,
arguments
);
};
return
DiscussionThreadListView
.
__super__
.
constructor
.
apply
(
this
,
arguments
);
// eslint-disable-line no-underscore-dangle, max-len
}
DiscussionThreadListView
.
prototype
.
events
=
{
'keypress .forum-nav-browse-filter-input'
:
function
(
event
)
{
return
DiscussionUtil
.
ignoreEnterKey
(
event
);
},
'keyup .forum-nav-browse-filter-input'
:
'filterTopics'
,
'keydown .forum-nav-browse-filter-input'
:
'keyboardBinding'
,
'click .forum-nav-browse-menu-wrapper'
:
'ignoreClick'
,
'click .forum-nav-browse-title'
:
'selectTopicHandler'
,
'change .forum-nav-sort-control'
:
'sortThreads'
,
'click .forum-nav-thread-link'
:
'threadSelected'
,
'click .forum-nav-load-more-link'
:
'loadMorePages'
,
...
...
@@ -117,8 +97,6 @@
this
.
collection
.
on
(
'change'
,
this
.
reloadDisplayedCollection
);
this
.
discussionIds
=
''
;
this
.
collection
.
on
(
'reset'
,
function
(
discussion
)
{
var
board
;
board
=
$
(
'.current-board'
).
html
();
self
.
displayedCollection
.
current_page
=
discussion
.
current_page
;
self
.
displayedCollection
.
pages
=
discussion
.
pages
;
return
self
.
displayedCollection
.
reset
(
discussion
.
models
);
...
...
@@ -129,23 +107,15 @@
this
.
boardName
=
null
;
this
.
current_search
=
''
;
this
.
mode
=
'all'
;
this
.
keyCodes
=
{
enter
:
13
,
escape
:
27
,
up
:
38
,
down
:
40
};
this
.
filterInputReset
();
this
.
selectedTopic
=
$
(
'.forum-nav-browse-menu-item:visible .forum-nav-browse-title.is-focused'
);
this
.
searchAlertCollection
=
new
Backbone
.
Collection
([],
{
model
:
Backbone
.
Model
});
this
.
searchAlertCollection
.
on
(
'add'
,
function
(
searchAlert
)
{
var
content
;
content
=
edx
.
HtmlUtils
.
template
(
$
(
'#search-alert-template'
).
html
())({
'messageHtml'
:
searchAlert
.
attributes
.
message
,
'cid'
:
searchAlert
.
cid
,
'css_class'
:
searchAlert
.
attributes
.
css_class
messageHtml
:
searchAlert
.
attributes
.
message
,
cid
:
searchAlert
.
cid
,
css_class
:
searchAlert
.
attributes
.
css_class
});
edx
.
HtmlUtils
.
append
(
self
.
$
(
'.search-alerts'
),
content
);
return
self
.
$
(
'#search-alert-'
+
searchAlert
.
cid
+
' .dismiss'
)
...
...
@@ -160,7 +130,6 @@
return
self
.
$
(
'.search-alerts'
).
empty
();
});
this
.
template
=
edx
.
HtmlUtils
.
template
(
$
(
'#thread-list-template'
).
html
());
this
.
homeTemplate
=
edx
.
HtmlUtils
.
template
(
$
(
'#discussion-home-template'
).
html
());
this
.
threadListItemTemplate
=
edx
.
HtmlUtils
.
template
(
$
(
'#thread-list-item-template'
).
html
());
};
...
...
@@ -172,10 +141,9 @@
* @returns {Backbone.Model}
*/
DiscussionThreadListView
.
prototype
.
addSearchAlert
=
function
(
message
,
cssClass
)
{
var
m
;
m
=
new
Backbone
.
Model
({
message
:
message
,
css_class
:
cssClass
||
''
});
this
.
searchAlertCollection
.
add
(
m
);
return
m
;
var
searchAlertModel
=
new
Backbone
.
Model
({
message
:
message
,
css_class
:
cssClass
||
''
});
this
.
searchAlertCollection
.
add
(
searchAlertModel
);
return
searchAlertModel
;
};
DiscussionThreadListView
.
prototype
.
removeSearchAlert
=
function
(
searchAlert
)
{
...
...
@@ -196,7 +164,7 @@
$currentElement
.
replaceWith
(
$content
);
this
.
showMetadataAccordingToSort
();
if
(
active
)
{
return
this
.
setActiveThread
(
threadId
);
this
.
setActiveThread
(
threadId
);
}
};
...
...
@@ -212,37 +180,6 @@
});
};
DiscussionThreadListView
.
prototype
.
updateSidebar
=
function
()
{
var
amount
,
browseFilterHeight
,
discussionBody
,
discussionBottomOffset
,
discussionsBodyBottom
,
discussionsBodyTop
,
headerHeight
,
refineBarHeight
,
scrollTop
,
sidebar
,
sidebarHeight
,
topOffset
,
windowHeight
;
scrollTop
=
$
(
window
).
scrollTop
();
windowHeight
=
$
(
window
).
height
();
discussionBody
=
$
(
'.discussion-column'
);
discussionsBodyTop
=
discussionBody
[
0
]
?
discussionBody
.
offset
().
top
:
void
0
;
discussionsBodyBottom
=
discussionsBodyTop
+
discussionBody
.
outerHeight
();
sidebar
=
$
(
'.forum-nav'
);
if
(
scrollTop
>
discussionsBodyTop
-
this
.
sidebar_padding
)
{
sidebar
.
css
(
'top'
,
scrollTop
-
discussionsBodyTop
+
this
.
sidebar_padding
);
}
else
{
sidebar
.
css
(
'top'
,
'0'
);
}
sidebarHeight
=
windowHeight
-
Math
.
max
(
discussionsBodyTop
-
scrollTop
,
this
.
sidebar_padding
);
topOffset
=
scrollTop
+
windowHeight
;
discussionBottomOffset
=
discussionsBodyBottom
+
this
.
sidebar_padding
;
amount
=
Math
.
max
(
topOffset
-
discussionBottomOffset
,
0
);
sidebarHeight
=
sidebarHeight
-
this
.
sidebar_padding
-
amount
;
sidebarHeight
=
Math
.
min
(
sidebarHeight
+
1
,
discussionBody
.
outerHeight
());
sidebar
.
css
(
'height'
,
sidebarHeight
);
headerHeight
=
this
.
$
(
'.forum-nav-header'
).
outerHeight
();
refineBarHeight
=
this
.
$
(
'.forum-nav-refine-bar'
).
outerHeight
();
browseFilterHeight
=
this
.
$
(
'.forum-nav-browse-filter'
).
outerHeight
();
this
.
$
(
'.forum-nav-thread-list'
)
.
css
(
'height'
,
(
sidebarHeight
-
headerHeight
-
refineBarHeight
-
2
)
+
'px'
);
this
.
$
(
'.forum-nav-browse-menu'
)
.
css
(
'height'
,
(
sidebarHeight
-
headerHeight
-
browseFilterHeight
-
2
)
+
'px'
);
};
DiscussionThreadListView
.
prototype
.
ignoreClick
=
function
(
event
)
{
return
event
.
stopPropagation
();
};
...
...
@@ -261,16 +198,14 @@
this
.
$
(
'.forum-nav-sort-control option'
).
removeProp
(
'selected'
);
this
.
$
(
'.forum-nav-sort-control option[value='
+
this
.
collection
.
sort_preference
+
']'
)
.
prop
(
'selected'
,
true
);
$
(
window
).
bind
(
'load scroll resize'
,
this
.
updateSidebar
);
this
.
displayedCollection
.
on
(
'reset'
,
this
.
renderThreads
);
this
.
displayedCollection
.
on
(
'thread:remove'
,
this
.
renderThreads
);
this
.
displayedCollection
.
on
(
'change:commentable_id'
,
function
()
{
if
(
self
.
mode
===
'commentables'
)
{
return
self
.
retrieveDiscussions
(
self
.
discussionIds
.
split
(
','
));
self
.
retrieveDiscussions
(
self
.
discussionIds
.
split
(
','
));
}
});
this
.
renderThreads
();
this
.
showBrowseMenu
(
true
);
return
this
;
};
...
...
@@ -284,7 +219,6 @@
}
this
.
showMetadataAccordingToSort
();
this
.
renderMorePages
();
this
.
updateSidebar
();
this
.
trigger
(
'threads:rendered'
);
};
...
...
@@ -319,7 +253,7 @@
};
DiscussionThreadListView
.
prototype
.
loadMorePages
=
function
(
event
)
{
var
error
,
lastThread
,
loadMoreElem
,
loadingElem
,
options
,
_
ref
,
var
error
,
lastThread
,
loadMoreElem
,
loadingElem
,
options
,
ref
,
self
=
this
;
if
(
event
)
{
event
.
preventDefault
();
...
...
@@ -353,9 +287,11 @@
if
(
this
.
group_id
)
{
options
.
group_id
=
this
.
group_id
;
}
break
;
default
:
}
_
ref
=
this
.
collection
.
last
();
lastThread
=
_ref
?
_
ref
.
get
(
'id'
)
:
void
0
;
ref
=
this
.
collection
.
last
();
lastThread
=
ref
?
ref
.
get
(
'id'
)
:
void
0
;
if
(
lastThread
)
{
this
.
once
(
'threads:rendered'
,
function
()
{
var
classSelector
=
...
...
@@ -365,8 +301,8 @@
});
}
else
{
this
.
once
(
'threads:rendered'
,
function
()
{
var
_
ref1
=
$
(
'.forum-nav-thread-link'
).
first
();
return
_ref1
?
_
ref1
.
focus
()
:
void
0
;
var
ref1
=
$
(
'.forum-nav-thread-link'
).
first
();
return
ref1
?
ref1
.
focus
()
:
void
0
;
});
}
error
=
function
()
{
...
...
@@ -421,224 +357,10 @@
.
prepend
(
$srElem
);
};
DiscussionThreadListView
.
prototype
.
goHome
=
function
()
{
var
url
,
$templateContent
;
$templateContent
=
$
(
this
.
homeTemplate
().
toString
());
$
(
'.forum-content'
).
empty
().
append
(
$templateContent
);
$
(
'.forum-nav-thread-list a'
).
removeClass
(
'is-active'
).
find
(
'.sr'
)
.
remove
();
$
(
'input.email-setting'
).
bind
(
'click'
,
this
.
updateEmailNotifications
);
url
=
DiscussionUtil
.
urlFor
(
'notifications_status'
,
window
.
user
.
get
(
'id'
));
DiscussionUtil
.
safeAjax
({
url
:
url
,
type
:
'GET'
,
success
:
function
(
response
)
{
$
(
'input.email-setting'
).
prop
(
'checked'
,
response
.
status
);
}
});
};
DiscussionThreadListView
.
prototype
.
isBrowseMenuVisible
=
function
()
{
return
this
.
$
(
'.forum-nav-browse-menu-wrapper'
).
is
(
':visible'
);
};
DiscussionThreadListView
.
prototype
.
showBrowseMenu
=
function
(
initialLoad
)
{
if
(
!
this
.
isBrowseMenuVisible
())
{
this
.
$
(
'.forum-nav-browse-menu-wrapper'
).
show
();
this
.
$
(
'.forum-nav-thread-list-wrapper'
).
hide
();
if
(
!
initialLoad
)
{
$
(
'.forum-nav-browse-filter-input'
).
focus
();
this
.
filterInputReset
();
}
$
(
'body'
).
bind
(
'click'
,
this
.
hideBrowseMenu
);
return
this
.
updateSidebar
();
}
};
DiscussionThreadListView
.
prototype
.
hideBrowseMenu
=
function
()
{
var
selectedTopicList
=
this
.
$
(
'.forum-nav-browse-title.is-focused'
);
if
(
this
.
isBrowseMenuVisible
())
{
selectedTopicList
.
removeClass
(
'is-focused'
);
this
.
$
(
'.forum-nav-browse-menu-wrapper'
).
hide
();
this
.
$
(
'.forum-nav-thread-list-wrapper'
).
show
();
if
(
this
.
selectedTopicId
!==
'undefined'
)
{
this
.
$
(
'.forum-nav-browse-filter-input'
).
attr
(
'aria-activedescendant'
,
this
.
selectedTopicId
);
}
$
(
'body'
).
unbind
(
'click'
,
this
.
hideBrowseMenu
);
return
this
.
updateSidebar
();
}
};
DiscussionThreadListView
.
prototype
.
toggleBrowseMenu
=
function
(
event
)
{
var
inputText
=
$
(
'.forum-nav-browse-filter-input'
).
val
();
event
.
preventDefault
();
event
.
stopPropagation
();
if
(
this
.
isBrowseMenuVisible
())
{
return
this
.
hideBrowseMenu
();
}
else
{
if
(
inputText
!==
''
)
{
this
.
filterTopics
(
inputText
);
}
return
this
.
showBrowseMenu
();
}
};
DiscussionThreadListView
.
prototype
.
getPathText
=
function
(
item
)
{
var
path
,
pathTitles
;
path
=
item
.
parents
(
'.forum-nav-browse-menu-item'
).
andSelf
();
pathTitles
=
path
.
children
(
'.forum-nav-browse-title'
).
map
(
function
(
i
,
elem
)
{
return
$
(
elem
).
text
();
}).
get
();
return
pathTitles
.
join
(
' / '
);
};
DiscussionThreadListView
.
prototype
.
getBreadcrumbText
=
function
(
$item
)
{
var
$parentSubMenus
=
$item
.
parents
(
'.forum-nav-browse-submenu'
),
crumbs
=
[],
subTopic
=
$
(
'.forum-nav-browse-title'
,
$item
)
.
first
()
.
text
()
.
trim
();
$parentSubMenus
.
each
(
function
(
i
,
el
)
{
crumbs
.
push
(
$
(
el
).
siblings
(
'.forum-nav-browse-title'
)
.
first
()
.
text
()
.
trim
()
);
});
if
(
subTopic
!==
'All Discussions'
)
{
crumbs
.
push
(
subTopic
);
}
return
crumbs
;
};
DiscussionThreadListView
.
prototype
.
selectOption
=
function
(
element
)
{
var
activeDescendantId
,
activeDescendantText
;
if
(
this
.
selectedTopic
.
length
>
0
)
{
this
.
selectedTopic
.
removeClass
(
'is-focused'
);
}
if
(
element
)
{
element
.
addClass
(
'is-focused'
);
activeDescendantId
=
element
.
parent
().
attr
(
'id'
);
activeDescendantText
=
element
.
text
();
this
.
selectedTopic
=
element
;
this
.
selectedTopicId
=
activeDescendantId
;
$
(
'.forum-nav-browse-filter-input'
)
.
attr
(
'aria-activedescendant'
,
activeDescendantId
)
.
val
(
activeDescendantText
);
}
};
DiscussionThreadListView
.
prototype
.
filterInputReset
=
function
()
{
this
.
filterEnabled
=
true
;
this
.
selectedTopicIndex
=
-
1
;
this
.
selectedTopicId
=
null
;
};
DiscussionThreadListView
.
prototype
.
keyboardBinding
=
function
(
event
)
{
var
$inputText
=
$
(
'.forum-nav-browse-filter-input'
),
$filteredMenuItems
=
$
(
'.forum-nav-browse-menu-item:visible'
),
filteredMenuItemsLen
=
$filteredMenuItems
.
length
,
$curOption
=
$filteredMenuItems
.
eq
(
0
).
find
(
'.forum-nav-browse-title'
).
eq
(
0
),
$activeOption
,
$prev
,
$next
;
switch
(
event
.
keyCode
)
{
case
this
.
keyCodes
.
enter
:
$activeOption
=
$filteredMenuItems
.
find
(
'.forum-nav-browse-title.is-focused'
);
if
(
$inputText
.
val
()
!==
''
)
{
$activeOption
.
trigger
(
'click'
);
this
.
filterInputReset
();
}
break
;
case
this
.
keyCodes
.
escape
:
this
.
toggleBrowseMenu
(
event
);
$
(
'.forum-nav-browse-filter-input'
).
val
(
''
);
this
.
filterInputReset
();
$
(
'.all-topics'
).
trigger
(
'click'
);
break
;
case
this
.
keyCodes
.
up
:
if
(
this
.
selectedTopicIndex
>
0
)
{
this
.
selectedTopicIndex
-=
1
;
if
(
this
.
isBrowseMenuVisible
())
{
$prev
=
$
(
'.forum-nav-browse-menu-item:visible'
)
.
eq
(
this
.
selectedTopicIndex
).
find
(
'.forum-nav-browse-title'
)
.
eq
(
0
);
this
.
filterEnabled
=
false
;
$curOption
.
removeClass
(
'is-focused'
);
$prev
.
addClass
(
'is-focused'
);
}
this
.
selectOption
(
$prev
);
}
break
;
case
this
.
keyCodes
.
down
:
if
(
this
.
selectedTopicIndex
<
filteredMenuItemsLen
-
1
)
{
this
.
selectedTopicIndex
+=
1
;
if
(
this
.
isBrowseMenuVisible
())
{
$next
=
$
(
'.forum-nav-browse-menu-item:visible'
)
.
eq
(
this
.
selectedTopicIndex
).
find
(
'.forum-nav-browse-title'
)
.
eq
(
0
);
this
.
filterEnabled
=
false
;
$curOption
.
removeClass
(
'is-focused'
);
$next
.
addClass
(
'is-focused'
);
}
this
.
selectOption
(
$next
);
}
break
;
default
:
break
;
}
return
true
;
};
DiscussionThreadListView
.
prototype
.
filterTopics
=
function
()
{
var
items
,
query
,
filteredItems
,
self
=
this
;
query
=
this
.
$
(
'.forum-nav-browse-filter-input'
).
val
();
items
=
this
.
$
(
'.forum-nav-browse-menu-item'
);
if
(
query
.
length
===
0
)
{
items
.
find
(
'.forum-nav-browse-title.is-focused'
).
removeClass
(
'is-focused'
);
return
items
.
show
();
}
else
{
if
(
this
.
filterEnabled
)
{
items
.
hide
();
filteredItems
=
items
.
each
(
function
(
i
,
item
)
{
var
path
,
pathText
,
$item
=
$
(
item
);
if
(
!
$item
.
is
(
':visible'
))
{
pathText
=
self
.
getPathText
(
$item
).
toLowerCase
();
if
(
query
.
split
(
' '
).
every
(
function
(
term
)
{
return
pathText
.
search
(
term
.
toLowerCase
())
!==
-
1
;
}))
{
path
=
$item
.
parents
(
'.forum-nav-browse-menu-item'
).
andSelf
();
return
path
.
add
(
$item
.
find
(
'.forum-nav-browse-menu-item'
)).
show
();
}
}
return
filteredItems
;
});
}
return
filteredItems
;
}
};
DiscussionThreadListView
.
prototype
.
selectTopicHandler
=
function
(
event
)
{
event
.
preventDefault
();
return
this
.
selectTopic
(
$
(
event
.
target
));
};
DiscussionThreadListView
.
prototype
.
selectTopic
=
function
(
$target
)
{
var
allItems
,
discussionIds
,
$item
;
this
.
hideBrowseMenu
();
$item
=
$target
.
closest
(
'.forum-nav-browse-menu-item'
);
this
.
trigger
(
'topic:selected'
,
this
.
getBreadcrumbText
(
$item
));
if
(
$item
.
hasClass
(
'forum-nav-browse-menu-all'
))
{
this
.
discussionIds
=
''
;
this
.
$
(
'.forum-nav-filter-cohort'
).
show
();
...
...
@@ -667,9 +389,8 @@
};
DiscussionThreadListView
.
prototype
.
retrieveDiscussion
=
function
(
discussionId
,
callback
)
{
var
url
,
var
url
=
DiscussionUtil
.
urlFor
(
'retrieve_discussion'
,
discussionId
)
,
self
=
this
;
url
=
DiscussionUtil
.
urlFor
(
'retrieve_discussion'
,
discussionId
);
return
DiscussionUtil
.
safeAjax
({
url
:
url
,
type
:
'GET'
,
...
...
@@ -686,8 +407,8 @@
});
};
DiscussionThreadListView
.
prototype
.
retrieveDiscussions
=
function
(
discussion
_i
ds
)
{
this
.
discussionIds
=
discussion
_i
ds
.
join
(
','
);
DiscussionThreadListView
.
prototype
.
retrieveDiscussions
=
function
(
discussion
I
ds
)
{
this
.
discussionIds
=
discussion
I
ds
.
join
(
','
);
this
.
mode
=
'commentables'
;
return
this
.
retrieveFirstPage
();
};
...
...
@@ -709,19 +430,18 @@
};
DiscussionThreadListView
.
prototype
.
performSearch
=
function
(
$searchInput
)
{
this
.
hideBrowseMenu
();
// trigger this event so the breadcrumbs can update as well
this
.
trigger
(
'search:initiated'
);
this
.
searchFor
(
$searchInput
.
val
(),
$searchInput
);
};
DiscussionThreadListView
.
prototype
.
searchFor
=
function
(
text
,
$searchInput
)
{
var
url
,
self
=
this
;
var
url
=
DiscussionUtil
.
urlFor
(
'search'
),
self
=
this
;
this
.
clearSearchAlerts
();
this
.
clearFilters
();
this
.
mode
=
'search'
;
this
.
current_search
=
text
;
url
=
DiscussionUtil
.
urlFor
(
'search'
);
/*
TODO: This might be better done by setting discussion.current_page=0 and
calling discussion.loadMorePages
...
...
@@ -789,6 +509,7 @@
return
self
.
searchForUser
(
text
);
}
}
return
response
;
}
});
};
...
...
@@ -816,9 +537,9 @@
);
message
=
edx
.
HtmlUtils
.
interpolateHtml
(
gettext
(
'Show posts by {username}.'
),
{
'username'
:
username
}
gettext
(
'Show posts by {username}.'
),
{
username
:
username
}
);
return
self
.
addSearchAlert
(
message
,
'search-by-user'
);
self
.
addSearchAlert
(
message
,
'search-by-user'
);
}
}
});
...
...
common/static/common/js/spec/discussion/view/discussion_thread_edit_view_spec.js
View file @
57fa123f
...
...
@@ -16,7 +16,7 @@
'title'
:
'test thread title'
});
this
.
thread
=
new
Thread
(
this
.
threadData
);
this
.
course_settings
=
DiscussionSpecHelper
.
make
CourseSettings
();
this
.
course_settings
=
DiscussionSpecHelper
.
createTest
CourseSettings
();
this
.
createEditView
=
function
(
options
)
{
options
=
_
.
extend
({
...
...
common/static/common/js/spec/discussion/view/discussion_thread_list_view_spec.js
View file @
57fa123f
...
...
@@ -266,6 +266,88 @@
changeSorting
(
this
.
threads
,
'votes'
,
'comments'
,
[
'Thread1'
,
'Thread4'
,
'Thread3'
,
'Thread2'
]);
});
});
describe
(
'post type renders correctly'
,
function
()
{
it
(
'for discussion'
,
function
()
{
renderSingleThreadWithProps
({
thread_type
:
'discussion'
});
expect
(
$
(
'.forum-nav-thread-wrapper-0 .icon'
)).
toHaveClass
(
'fa-comments'
);
return
expect
(
$
(
'.forum-nav-thread-wrapper-0 .sr'
)).
toHaveText
(
'discussion'
);
});
it
(
'for answered question'
,
function
()
{
renderSingleThreadWithProps
({
thread_type
:
'question'
,
endorsed
:
true
});
expect
(
$
(
'.forum-nav-thread-wrapper-0 .icon'
)).
toHaveClass
(
'fa-check-square-o'
);
return
expect
(
$
(
'.forum-nav-thread-wrapper-0 .sr'
)).
toHaveText
(
'answered question'
);
});
it
(
'for unanswered question'
,
function
()
{
renderSingleThreadWithProps
({
thread_type
:
'question'
,
endorsed
:
false
});
expect
(
$
(
'.forum-nav-thread-wrapper-0 .icon'
)).
toHaveClass
(
'fa-question'
);
return
expect
(
$
(
'.forum-nav-thread-wrapper-0 .sr'
)).
toHaveText
(
'unanswered question'
);
});
});
describe
(
'post labels render correctly'
,
function
()
{
beforeEach
(
function
()
{
this
.
moderatorId
=
'42'
;
this
.
administratorId
=
'43'
;
this
.
communityTaId
=
'44'
;
return
DiscussionUtil
.
loadRoles
({
Moderator
:
[
parseInt
(
this
.
moderatorId
,
10
)],
Administrator
:
[
parseInt
(
this
.
administratorId
,
10
)],
'Community TA'
:
[
parseInt
(
this
.
communityTaId
,
10
)]
});
});
it
(
'for pinned'
,
function
()
{
renderSingleThreadWithProps
({
pinned
:
true
});
return
expect
(
$
(
'.post-label-pinned'
).
length
).
toEqual
(
1
);
});
it
(
'for following'
,
function
()
{
renderSingleThreadWithProps
({
subscribed
:
true
});
return
expect
(
$
(
'.post-label-following'
).
length
).
toEqual
(
1
);
});
it
(
'for moderator'
,
function
()
{
renderSingleThreadWithProps
({
user_id
:
this
.
moderatorId
});
return
expect
(
$
(
'.post-label-by-staff'
).
length
).
toEqual
(
1
);
});
it
(
'for administrator'
,
function
()
{
renderSingleThreadWithProps
({
user_id
:
this
.
administratorId
});
return
expect
(
$
(
'.post-label-by-staff'
).
length
).
toEqual
(
1
);
});
it
(
'for community TA'
,
function
()
{
renderSingleThreadWithProps
({
user_id
:
this
.
communityTaId
});
return
expect
(
$
(
'.post-label-by-community-ta'
).
length
).
toEqual
(
1
);
});
it
(
'when none should be present'
,
function
()
{
renderSingleThreadWithProps
({});
return
expect
(
$
(
'.forum-nav-thread-labels'
).
length
).
toEqual
(
0
);
});
});
describe
(
'search alerts'
,
function
()
{
var
testAlertMessages
,
getAlertMessagesAndClasses
;
...
...
@@ -460,228 +542,5 @@
});
});
describe
(
'post type renders correctly'
,
function
()
{
it
(
'for discussion'
,
function
()
{
renderSingleThreadWithProps
({
thread_type
:
'discussion'
});
expect
(
$
(
'.forum-nav-thread-wrapper-0 .icon'
)).
toHaveClass
(
'fa-comments'
);
return
expect
(
$
(
'.forum-nav-thread-wrapper-0 .sr'
)).
toHaveText
(
'discussion'
);
});
it
(
'for answered question'
,
function
()
{
renderSingleThreadWithProps
({
thread_type
:
'question'
,
endorsed
:
true
});
expect
(
$
(
'.forum-nav-thread-wrapper-0 .icon'
)).
toHaveClass
(
'fa-check-square-o'
);
return
expect
(
$
(
'.forum-nav-thread-wrapper-0 .sr'
)).
toHaveText
(
'answered question'
);
});
it
(
'for unanswered question'
,
function
()
{
renderSingleThreadWithProps
({
thread_type
:
'question'
,
endorsed
:
false
});
expect
(
$
(
'.forum-nav-thread-wrapper-0 .icon'
)).
toHaveClass
(
'fa-question'
);
return
expect
(
$
(
'.forum-nav-thread-wrapper-0 .sr'
)).
toHaveText
(
'unanswered question'
);
});
});
describe
(
'post labels render correctly'
,
function
()
{
beforeEach
(
function
()
{
this
.
moderatorId
=
'42'
;
this
.
administratorId
=
'43'
;
this
.
communityTaId
=
'44'
;
return
DiscussionUtil
.
loadRoles
({
'Moderator'
:
[
parseInt
(
this
.
moderatorId
)],
'Administrator'
:
[
parseInt
(
this
.
administratorId
)],
'Community TA'
:
[
parseInt
(
this
.
communityTaId
)]
});
});
it
(
'for pinned'
,
function
()
{
renderSingleThreadWithProps
({
pinned
:
true
});
return
expect
(
$
(
'.post-label-pinned'
).
length
).
toEqual
(
1
);
});
it
(
'for following'
,
function
()
{
renderSingleThreadWithProps
({
subscribed
:
true
});
return
expect
(
$
(
'.post-label-following'
).
length
).
toEqual
(
1
);
});
it
(
'for moderator'
,
function
()
{
renderSingleThreadWithProps
({
user_id
:
this
.
moderatorId
});
return
expect
(
$
(
'.post-label-by-staff'
).
length
).
toEqual
(
1
);
});
it
(
'for administrator'
,
function
()
{
renderSingleThreadWithProps
({
user_id
:
this
.
administratorId
});
return
expect
(
$
(
'.post-label-by-staff'
).
length
).
toEqual
(
1
);
});
it
(
'for community TA'
,
function
()
{
renderSingleThreadWithProps
({
user_id
:
this
.
communityTaId
});
return
expect
(
$
(
'.post-label-by-community-ta'
).
length
).
toEqual
(
1
);
});
it
(
'when none should be present'
,
function
()
{
renderSingleThreadWithProps
({});
return
expect
(
$
(
'.forum-nav-thread-labels'
).
length
).
toEqual
(
0
);
});
});
describe
(
'browse menu'
,
function
()
{
var
expectBrowseMenuVisible
;
afterEach
(
function
()
{
return
$
(
'body'
).
unbind
(
'click'
);
});
expectBrowseMenuVisible
=
function
(
isVisible
)
{
expect
(
$
(
'.forum-nav-browse-menu:visible'
).
length
).
toEqual
(
isVisible
?
1
:
0
);
return
expect
(
$
(
'.forum-nav-thread-list-wrapper:visible'
).
length
).
toEqual
(
isVisible
?
0
:
1
);
};
it
(
'should be visible by default'
,
function
()
{
expectBrowseMenuVisible
(
true
);
});
it
(
'should disappear when header button is clicked'
,
function
()
{
$
(
'.forum-nav-browse'
).
click
();
return
expectBrowseMenuVisible
(
false
);
});
describe
(
'when shown'
,
function
()
{
it
(
'should show again when header button is clicked'
,
function
()
{
$
(
'.forum-nav-browse'
).
click
();
return
expectBrowseMenuVisible
(
false
);
});
it
(
'should hide when a click outside the menu occurs'
,
function
()
{
$
(
'.forum-nav-search-input'
).
click
();
return
expectBrowseMenuVisible
(
false
);
});
it
(
'should hide when a category is clicked'
,
function
()
{
$
(
'.forum-nav-browse-title'
)[
0
].
click
();
return
expectBrowseMenuVisible
(
false
);
});
it
(
'should still be shown when filter input is clicked'
,
function
()
{
$
(
'.forum-nav-browse-filter-input'
).
click
();
return
expectBrowseMenuVisible
(
true
);
});
describe
(
'filtering'
,
function
()
{
var
checkFilter
;
checkFilter
=
function
(
filterText
,
expectedItems
)
{
var
visibleItems
;
$
(
'.forum-nav-browse-filter-input'
).
val
(
filterText
).
keyup
();
visibleItems
=
$
(
'.forum-nav-browse-title:visible'
).
map
(
function
(
i
,
elem
)
{
return
$
(
elem
).
text
();
}).
get
();
return
expect
(
visibleItems
).
toEqual
(
expectedItems
);
};
it
(
'should be case-insensitive'
,
function
()
{
return
checkFilter
(
'other'
,
[
'Other Category'
]);
});
it
(
'should match partial words'
,
function
()
{
return
checkFilter
(
'ateg'
,
[
'Other Category'
]);
});
it
(
'should show ancestors and descendants of matches'
,
function
()
{
return
checkFilter
(
'Target'
,
[
'Parent'
,
'Target'
,
'Child'
]);
});
it
(
'should handle multiple words regardless of order'
,
function
()
{
return
checkFilter
(
'Following Posts'
,
[
"Posts I'm Following"
]);
});
it
(
'should handle multiple words in different depths'
,
function
()
{
return
checkFilter
(
'Parent Child'
,
[
'Parent'
,
'Target'
,
'Child'
]);
});
});
});
describe
(
'selecting an item'
,
function
()
{
var
testSelectionRequest
;
it
(
'should show/hide the cohort selector'
,
function
()
{
var
self
=
this
;
DiscussionSpecHelper
.
makeModerator
();
this
.
view
.
render
();
setupAjax
();
return
_
.
each
([
{
selector
:
'.forum-nav-browse-menu-all'
,
cohortVisibility
:
true
},
{
selector
:
'.forum-nav-browse-menu-following'
,
cohortVisibility
:
false
},
{
selector
:
'.forum-nav-browse-menu-item:'
+
'has(.forum-nav-browse-menu-item .forum-nav-browse-menu-item)'
,
cohortVisibility
:
false
},
{
selector
:
'[data-discussion-id=child]'
,
cohortVisibility
:
false
},
{
selector
:
'[data-discussion-id=other]'
,
cohortVisibility
:
true
}
],
function
(
itemInfo
)
{
self
.
view
.
$
(
''
+
itemInfo
.
selector
+
' > .forum-nav-browse-title'
).
click
();
return
expect
(
self
.
view
.
$
(
'.forum-nav-filter-cohort'
).
is
(
':visible'
))
.
toEqual
(
itemInfo
.
cohortVisibility
);
});
});
testSelectionRequest
=
function
(
callback
,
itemText
)
{
setupAjax
(
callback
);
$
(
'.forum-nav-browse-title:contains('
+
itemText
+
')'
).
click
();
return
expect
(
$
.
ajax
).
toHaveBeenCalled
();
};
it
(
'should get all discussions'
,
function
()
{
return
testSelectionRequest
(
function
(
params
)
{
return
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
'threads'
));
},
'All'
);
});
it
(
'should get followed threads'
,
function
()
{
testSelectionRequest
(
function
(
params
)
{
return
expect
(
params
.
url
.
path
())
.
toEqual
(
DiscussionUtil
.
urlFor
(
'followed_threads'
,
window
.
user
.
id
));
},
'Following'
);
return
expect
(
$
.
ajax
.
calls
.
mostRecent
().
args
[
0
].
data
.
group_id
).
toBeUndefined
();
});
it
(
'should get threads for the selected leaf'
,
function
()
{
return
testSelectionRequest
(
function
(
params
)
{
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
'search'
));
return
expect
(
params
.
data
.
commentable_ids
).
toEqual
(
'child'
);
},
'Child'
);
});
it
(
'should get threads for children of the selected intermediate node'
,
function
()
{
return
testSelectionRequest
(
function
(
params
)
{
expect
(
params
.
url
.
path
()).
toEqual
(
DiscussionUtil
.
urlFor
(
'search'
));
return
expect
(
params
.
data
.
commentable_ids
).
toEqual
(
'child,sibling'
);
},
'Parent'
);
});
});
});
});
}).
call
(
this
);
common/static/common/js/spec/discussion/view/discussion_thread_show_view_spec.js
View file @
57fa123f
...
...
@@ -5,7 +5,7 @@
var
$$course_id
=
'$$course_id'
;
describe
(
'DiscussionThreadShowView'
,
function
()
{
beforeEach
(
function
()
{
DiscussionSpecHelper
.
setUpGlobals
();
DiscussionSpecHelper
.
setUpGlobals
(
{}
);
DiscussionSpecHelper
.
setUnderscoreFixtures
();
this
.
user
=
DiscussionUtil
.
getUser
();
this
.
threadData
=
{
...
...
common/static/common/js/spec/discussion/view/discussion_thread_view_spec.js
View file @
57fa123f
...
...
@@ -129,7 +129,7 @@
model
:
thread
,
el
:
$
(
'#fixture-element'
),
mode
:
mode
,
course_settings
:
DiscussionSpecHelper
.
make
CourseSettings
()
course_settings
:
DiscussionSpecHelper
.
createTest
CourseSettings
()
});
renderWithTestResponses
(
view
,
1
);
if
(
mode
===
'inline'
)
{
...
...
@@ -185,7 +185,7 @@
model
:
this
.
thread
,
el
:
$
(
'#fixture-element'
),
mode
:
'tab'
,
course_settings
:
DiscussionSpecHelper
.
make
CourseSettings
()
course_settings
:
DiscussionSpecHelper
.
createTest
CourseSettings
()
});
});
describe
(
'responses'
,
function
()
{
...
...
@@ -282,7 +282,7 @@
model
:
this
.
thread
,
el
:
$
(
'#fixture-element'
),
mode
:
'inline'
,
course_settings
:
DiscussionSpecHelper
.
make
CourseSettings
()
course_settings
:
DiscussionSpecHelper
.
createTest
CourseSettings
()
});
});
describe
(
'render'
,
function
()
{
...
...
@@ -397,7 +397,7 @@
model
:
this
.
thread
,
el
:
$
(
'#fixture-element'
),
mode
:
'tab'
,
course_settings
:
DiscussionSpecHelper
.
make
CourseSettings
()
course_settings
:
DiscussionSpecHelper
.
createTest
CourseSettings
()
});
});
generateContent
=
function
(
idStart
,
idEnd
)
{
...
...
@@ -465,7 +465,7 @@
model
:
this
.
thread
,
el
:
$
(
'#fixture-element'
),
mode
:
'tab'
,
course_settings
:
DiscussionSpecHelper
.
make
CourseSettings
()
course_settings
:
DiscussionSpecHelper
.
createTest
CourseSettings
()
});
});
it
(
"doesn't show report option if can_report ability is disabled"
,
function
()
{
...
...
common/static/common/js/spec/discussion/view/response_comment_view_spec.js
View file @
57fa123f
...
...
@@ -5,7 +5,7 @@
describe
(
'ResponseCommentView'
,
function
()
{
beforeEach
(
function
()
{
DiscussionSpecHelper
.
setUpGlobals
();
DiscussionSpecHelper
.
setUpGlobals
(
{}
);
this
.
comment
=
new
Comment
({
id
:
'01234567'
,
user_id
:
user
.
id
,
...
...
common/static/common/js/spec_helpers/discussion_spec_helper.js
View file @
57fa123f
/* global DiscussionCourseSettings, DiscussionUtil, DiscussionUser */
/* global
Content, Discussion,
DiscussionCourseSettings, DiscussionUtil, DiscussionUser */
(
function
()
{
'use strict'
;
this
.
DiscussionSpecHelper
=
(
function
()
{
function
DiscussionSpecHelper
()
{
}
DiscussionSpecHelper
.
setUpGlobals
=
function
()
{
DiscussionUtil
.
loadRoles
(
DiscussionSpecHelper
.
getTestRoleInfo
());
window
.
$$course_id
=
'edX/999/test'
;
window
.
user
=
new
DiscussionUser
(
DiscussionSpecHelper
.
getTestUserInfo
());
return
DiscussionUtil
.
setUser
(
window
.
user
);
DiscussionSpecHelper
.
setUpGlobals
=
function
(
opts
)
{
var
options
=
opts
||
{};
DiscussionUtil
.
loadRoles
(
options
.
roles
||
DiscussionSpecHelper
.
getTestRoleInfo
());
window
.
$$course_id
=
options
.
courseName
||
'edX/999/test'
;
window
.
user
=
new
DiscussionUser
(
options
.
userInfo
||
DiscussionSpecHelper
.
getTestUserInfo
());
DiscussionUtil
.
setUser
(
window
.
user
);
};
DiscussionSpecHelper
.
getTestUserInfo
=
function
()
{
...
...
@@ -50,7 +51,7 @@
return
jasmine
.
createSpyObj
(
'event'
,
[
'preventDefault'
,
'target'
]);
};
DiscussionSpecHelper
.
make
CourseSettings
=
function
()
{
DiscussionSpecHelper
.
createTest
CourseSettings
=
function
()
{
return
new
DiscussionCourseSettings
({
category_map
:
{
children
:
[[
'Test Topic'
,
'entry'
],
[
'Other Topic'
,
'entry'
]],
...
...
@@ -69,12 +70,24 @@
});
};
DiscussionSpecHelper
.
createTestDiscussion
=
function
(
options
)
{
var
sortPreference
=
options
.
sort_preference
,
threads
=
options
.
threads
||
[],
threadPages
=
options
.
thread_pages
||
1
,
contentInfo
=
options
.
content_info
;
DiscussionSpecHelper
.
setUpGlobals
(
options
);
if
(
contentInfo
)
{
Content
.
loadContentInfos
(
contentInfo
);
}
return
new
Discussion
(
threads
,
{
pages
:
threadPages
,
sort
:
sortPreference
});
};
DiscussionSpecHelper
.
setUnderscoreFixtures
=
function
()
{
var
templateFixture
,
templateName
,
templateNames
,
templateNamesNoTrailingTemplate
,
i
,
j
,
len
;
templateNames
=
[
'thread'
,
'thread-show'
,
'thread-edit'
,
'thread-response'
,
'thread-response-show'
,
'thread-response-edit'
,
'response-comment-show'
,
'response-comment-edit'
,
'thread-list-item'
,
'
discussion-home'
,
'
search-alert'
,
'new-post'
,
'thread-type'
,
'new-post-menu-entry'
,
'new-post-alert'
,
'search-alert'
,
'new-post'
,
'thread-type'
,
'new-post-menu-entry'
,
'new-post-alert'
,
'new-post-menu-category'
,
'topic'
,
'post-user-display'
,
'inline-discussion'
,
'pagination'
,
'profile-thread'
,
'customwmd-prompt'
,
'nav-loading'
];
...
...
common/test/acceptance/tests/discussion/test_discussion.py
View file @
57fa123f
...
...
@@ -511,6 +511,7 @@ class DiscussionOpenClosedThreadTest(BaseDiscussionTestCase):
page
.
a11y_audit
.
config
.
set_rules
({
'ignore'
:
[
'section'
,
# TODO: AC-491
'aria-required-children'
,
# TODO: AC-534
'color-contrast'
,
# Commented out for now because they reproducibly fail on Jenkins but not locally
]
})
...
...
@@ -520,6 +521,7 @@ class DiscussionOpenClosedThreadTest(BaseDiscussionTestCase):
page
.
a11y_audit
.
config
.
set_rules
({
'ignore'
:
[
'section'
,
# TODO: AC-491
'aria-required-children'
,
# TODO: AC-534
'color-contrast'
,
# Commented out for now because they reproducibly fail on Jenkins but not locally
]
})
...
...
lms/djangoapps/discussion/static/discussion/js/discussion_board_factory.js
View file @
57fa123f
...
...
@@ -5,38 +5,50 @@
[
'jquery'
,
'backbone'
,
'common/js/discussion/content'
,
'common/js/discussion/discussion'
,
'common/js/discussion/utils'
,
'common/js/discussion/models/discussion_course_settings'
,
'common/js/discussion/models/discussion_user'
,
'common/js/discussion/views/new_post_view'
,
'discussion/js/discussion_router'
,
'discussion/js/views/discussion_fake_breadcrumbs'
,
'discussion/js/views/discussion_search_view'
,
'common/js/discussion/views/new_post_view'
'discussion/js/views/discussion_board_view'
],
function
(
$
,
Backbone
,
DiscussionRouter
,
DiscussionFakeBreadcrumbs
,
DiscussionSearchView
,
NewPostView
)
{
function
(
$
,
Backbone
,
Content
,
Discussion
,
DiscussionUtil
,
DiscussionCourseSettings
,
DiscussionUser
,
NewPostView
,
DiscussionRouter
,
DiscussionBoardView
)
{
return
function
(
options
)
{
var
userInfo
=
options
.
user_info
,
sortPreference
=
options
.
sort_preference
,
threads
=
options
.
threads
,
threadPages
=
options
.
thread_pages
,
contentInfo
=
options
.
content_info
,
user
=
new
window
.
DiscussionUser
(
userInfo
),
user
=
new
DiscussionUser
(
userInfo
),
discussion
,
courseSettings
,
newPostView
,
discussionBoardView
,
router
,
breadcrumbs
,
BreadcrumbsModel
,
searchBox
,
routerEvents
;
// TODO:
Perhaps
eliminate usage of global variables when possible
window
.
DiscussionUtil
.
loadRoles
(
options
.
roles
);
// TODO: eliminate usage of global variables when possible
DiscussionUtil
.
loadRoles
(
options
.
roles
);
window
.
$$course_id
=
options
.
courseId
;
window
.
courseName
=
options
.
course_name
;
window
.
DiscussionUtil
.
setUser
(
user
);
DiscussionUtil
.
setUser
(
user
);
window
.
user
=
user
;
window
.
Content
.
loadContentInfos
(
contentInfo
);
Content
.
loadContentInfos
(
contentInfo
);
discussion
=
new
window
.
Discussion
(
threads
,
{
pages
:
threadPages
,
sort
:
sortPreference
});
courseSettings
=
new
window
.
DiscussionCourseSettings
(
options
.
course_settings
);
// Create a discussion model
discussion
=
new
Discussion
(
threads
,
{
pages
:
threadPages
,
sort
:
sortPreference
});
courseSettings
=
new
DiscussionCourseSettings
(
options
.
course_settings
);
// Create the discussion board view
discussionBoardView
=
new
DiscussionBoardView
({
el
:
$
(
'.discussion-board'
),
discussion
:
discussion
,
courseSettings
:
courseSettings
});
discussionBoardView
.
render
();
// Create the new post view
newPostView
=
new
NewPostView
({
...
...
@@ -47,59 +59,27 @@
});
newPostView
.
render
();
// Set up
the
router to manage the page's history
// Set up
a
router to manage the page's history
router
=
new
DiscussionRouter
({
courseId
:
options
.
courseId
,
discussion
:
discussion
,
courseSettings
:
courseSettings
,
discussionBoardView
:
discussionBoardView
,
newPostView
:
newPostView
});
router
.
start
();
// Initialize and render search box
searchBox
=
new
DiscussionSearchView
({
el
:
$
(
'.forum-search'
),
threadListView
:
router
.
nav
}).
render
();
// Initialize and render breadcrumbs
BreadcrumbsModel
=
Backbone
.
Model
.
extend
({
defaults
:
{
contents
:
[]
}
});
breadcrumbs
=
new
DiscussionFakeBreadcrumbs
({
el
:
$
(
'.has-breadcrumbs'
),
model
:
new
BreadcrumbsModel
(),
events
:
{
'click .all-topics'
:
function
(
event
)
{
event
.
preventDefault
();
searchBox
.
clearSearch
();
this
.
model
.
set
(
'contents'
,
[]);
router
.
navigate
(
''
,
{
trigger
:
true
});
router
.
nav
.
toggleBrowseMenu
(
event
);
}
}
}).
render
();
routerEvents
=
{
// Add new breadcrumbs and clear search box when the user selects topics
'topic:selected'
:
function
(
topic
)
{
breadcrumbs
.
model
.
set
(
'contents'
,
topic
);
router
.
discussionBoardView
.
breadcrumbs
.
model
.
set
(
'contents'
,
topic
);
},
// Clear search box when a thread is selected
'thread:selected'
:
function
()
{
searchBox
.
clearSearch
();
},
// Add 'Search Results' to breadcrumbs when user searches
'search:initiated'
:
function
()
{
breadcrumbs
.
model
.
set
(
'contents'
,
[
'Search Results'
]);
router
.
discussionBoardView
.
searchView
.
clearSearch
();
}
};
Object
.
keys
(
routerEvents
).
forEach
(
function
(
key
)
{
router
.
nav
.
on
(
key
,
routerEvents
[
key
]);
router
.
discussionBoardView
.
on
(
key
,
routerEvents
[
key
]);
});
};
});
...
...
lms/djangoapps/discussion/static/discussion/js/discussion_profile_page_factory.js
View file @
57fa123f
(
function
(
define
)
{
'use strict'
;
define
([
'jquery'
,
'discussion/js/views/discussion_user_profile_view'
],
function
(
$
,
DiscussionUserProfileView
)
{
define
(
[
'jquery'
,
'common/js/discussion/utils'
,
'common/js/discussion/models/discussion_user'
,
'discussion/js/views/discussion_user_profile_view'
],
function
(
$
,
DiscussionUtil
,
DiscussionUser
,
DiscussionUserProfileView
)
{
return
function
(
options
)
{
var
$element
=
options
.
$el
,
threads
=
options
.
threads
,
...
...
@@ -10,13 +16,16 @@
page
=
options
.
page
,
numPages
=
options
.
numPages
;
// Roles are not included in user profile page, but they are not used for anything
window
.
DiscussionUtil
.
loadRoles
({
DiscussionUtil
.
loadRoles
({
Moderator
:
[],
Administrator
:
[],
'Community TA'
:
[]
});
// TODO: remove global variable usage
window
.
$$course_id
=
options
.
courseId
;
window
.
user
=
new
window
.
DiscussionUser
(
userInfo
);
window
.
user
=
new
DiscussionUser
(
userInfo
);
new
DiscussionUserProfileView
({
// eslint-disable-line no-new
el
:
$element
,
collection
:
threads
,
...
...
lms/djangoapps/discussion/static/discussion/js/discussion_router.js
View file @
57fa123f
...
...
@@ -6,10 +6,10 @@
'underscore'
,
'backbone'
,
'common/js/discussion/utils'
,
'common/js/discussion/
views/discussion_thread_list_view
'
,
'common/js/discussion/
models/discussion_course_settings
'
,
'common/js/discussion/views/discussion_thread_view'
],
function
(
_
,
Backbone
,
DiscussionUtil
,
Discussion
ThreadListView
,
DiscussionThreadView
)
{
function
(
_
,
Backbone
,
DiscussionUtil
,
Discussion
CourseSettings
,
DiscussionThreadView
)
{
var
DiscussionRouter
=
Backbone
.
Router
.
extend
({
routes
:
{
''
:
'allThreads'
,
...
...
@@ -21,14 +21,9 @@
_
.
bindAll
(
this
,
'allThreads'
,
'showThread'
);
this
.
courseId
=
options
.
courseId
;
this
.
discussion
=
options
.
discussion
;
this
.
course_settings
=
options
.
courseSettings
;
this
.
course_settings
=
new
DiscussionCourseSettings
(
options
.
course_settings
);
this
.
discussionBoardView
=
options
.
discussionBoardView
;
this
.
newPostView
=
options
.
newPostView
;
this
.
nav
=
new
DiscussionThreadListView
({
collection
:
this
.
discussion
,
el
:
$
(
'.forum-nav'
),
courseSettings
:
this
.
course_settings
});
this
.
nav
.
render
();
},
start
:
function
()
{
...
...
@@ -41,10 +36,18 @@
});
// Automatically navigate when the user selects threads
this
.
nav
.
on
(
'thread:selected'
,
_
.
bind
(
this
.
navigateToThread
,
this
));
this
.
nav
.
on
(
'thread:removed'
,
_
.
bind
(
this
.
navigateToAllThreads
,
this
));
this
.
nav
.
on
(
'threads:rendered'
,
_
.
bind
(
this
.
setActiveThread
,
this
));
this
.
nav
.
on
(
'thread:created'
,
_
.
bind
(
this
.
navigateToThread
,
this
));
this
.
discussionBoardView
.
discussionThreadListView
.
on
(
'thread:selected'
,
_
.
bind
(
this
.
navigateToThread
,
this
)
);
this
.
discussionBoardView
.
discussionThreadListView
.
on
(
'thread:removed'
,
_
.
bind
(
this
.
navigateToAllThreads
,
this
)
);
this
.
discussionBoardView
.
discussionThreadListView
.
on
(
'threads:rendered'
,
_
.
bind
(
this
.
setActiveThread
,
this
)
);
this
.
discussionBoardView
.
discussionThreadListView
.
on
(
'thread:created'
,
_
.
bind
(
this
.
navigateToThread
,
this
)
);
Backbone
.
history
.
start
({
pushState
:
true
,
...
...
@@ -57,15 +60,15 @@
},
allThreads
:
function
()
{
this
.
nav
.
updateSidebar
();
return
this
.
nav
.
goHome
();
this
.
discussionBoardView
.
updateSidebar
();
return
this
.
discussionBoardView
.
goHome
();
},
setActiveThread
:
function
()
{
if
(
this
.
thread
)
{
return
this
.
nav
.
setActiveThread
(
this
.
thread
.
get
(
'id'
));
return
this
.
discussionBoardView
.
discussionThreadListView
.
setActiveThread
(
this
.
thread
.
get
(
'id'
));
}
else
{
return
this
.
nav
.
goHome
;
return
this
.
discussionBoardView
.
goHome
;
}
},
...
...
@@ -86,8 +89,8 @@
if
(
!
(
$
(
'.forum-content'
).
is
(
':visible'
)))
{
$
(
'.forum-content'
).
fadeIn
();
}
if
(
this
.
newPostView
.
$el
.
is
(
':visible'
))
{
this
.
newPostView
.
$el
.
fadeOut
();
if
(
$
(
'.new-post-article'
)
.
is
(
':visible'
))
{
$
(
'.new-post-article'
)
.
fadeOut
();
}
this
.
main
=
new
DiscussionThreadView
({
el
:
$
(
'.forum-content'
),
...
...
@@ -97,14 +100,13 @@
});
this
.
main
.
render
();
this
.
main
.
on
(
'thread:responses:rendered'
,
function
()
{
return
self
.
nav
.
updateSidebar
();
return
self
.
discussionBoardView
.
updateSidebar
();
});
return
this
.
thread
.
on
(
'thread:thread_type_updated'
,
this
.
showMain
);
},
navigateToThread
:
function
(
threadId
)
{
var
thread
;
thread
=
this
.
discussion
.
get
(
threadId
);
var
thread
=
this
.
discussion
.
get
(
threadId
);
return
this
.
navigate
(
''
+
(
thread
.
get
(
'commentable_id'
))
+
'/threads/'
+
threadId
,
{
trigger
:
true
});
...
...
@@ -135,6 +137,7 @@
}
});
}
});
return
DiscussionRouter
;
...
...
lms/djangoapps/discussion/static/discussion/js/spec/discussion_board_factory_spec.js
View file @
57fa123f
...
...
@@ -4,16 +4,34 @@ define(
'backbone'
,
'common/js/spec_helpers/page_helpers'
,
'common/js/spec_helpers/discussion_spec_helper'
,
'discussion/js/discussion_board_factory'
'discussion/js/discussion_board_factory'
,
'discussion/js/views/discussion_board_view'
],
function
(
$
,
Backbone
,
PageHelpers
,
DiscussionSpecHelper
,
DiscussionBoardFactory
)
{
function
(
$
,
Backbone
,
PageHelpers
,
DiscussionSpecHelper
,
DiscussionBoardFactory
,
DiscussionBoardView
)
{
'use strict'
;
// TODO: re-enable when this doesn't interact badly with other history tests
xdescribe
(
'Discussion Board Factory'
,
function
()
{
describe
(
'DiscussionBoardFactory'
,
function
()
{
var
createDiscussionBoardView
=
function
()
{
var
discussionBoardView
,
discussion
=
DiscussionSpecHelper
.
createTestDiscussion
({}),
courseSettings
=
DiscussionSpecHelper
.
createTestCourseSettings
();
setFixtures
(
'<div class="discussion-board"><div class="forum-search"></div></div>'
);
DiscussionSpecHelper
.
setUnderscoreFixtures
();
discussionBoardView
=
new
DiscussionBoardView
({
el
:
$
(
'.discussion-board'
),
discussion
:
discussion
,
courseSettings
:
courseSettings
});
return
discussionBoardView
;
};
var
initializeDiscussionBoardFactory
=
function
()
{
DiscussionBoardFactory
({
el
:
$
(
'
.discussion-board
'
),
el
:
$
(
'
#discussion-container
'
),
courseId
:
'test_course_id'
,
course_name
:
'Test Course'
,
user_info
:
DiscussionSpecHelper
.
getTestUserInfo
(),
...
...
@@ -33,14 +51,11 @@ define(
};
beforeEach
(
function
()
{
PageHelpers
.
preventBackboneChangingUrl
();
// Install the fixtures
setFixtures
(
'<div class="discussion-board">'
+
' <div class="forum-nav"></div>'
+
'</div>'
'<div id="discussion-container" class="discussion-board"></div></div>'
);
PageHelpers
.
preventBackboneChangingUrl
();
DiscussionSpecHelper
.
setUnderscoreFixtures
();
});
...
...
@@ -48,9 +63,11 @@ define(
Backbone
.
history
.
stop
();
});
it
(
'can render itself'
,
function
()
{
xit
(
'can render itself'
,
function
()
{
// this failed Search: navigates to search, and TeamsTab
var
discussionView
=
createDiscussionBoardView
();
discussionView
.
render
();
initializeDiscussionBoardFactory
();
expect
(
$
(
'.discussion-board'
).
text
()).
toContain
(
'All Discussion
s'
);
expect
(
discussionView
.
$el
.
text
()).
toContain
(
'Search all post
s'
);
});
});
}
...
...
lms/djangoapps/discussion/static/discussion/js/spec/discussion_board_view_spec.js
0 → 100644
View file @
57fa123f
/* globals Discussion, DiscussionCourseSettings */
(
function
(
define
)
{
'use strict'
;
define
(
[
'underscore'
,
'jquery'
,
'edx-ui-toolkit/js/utils/constants'
,
'common/js/discussion/discussion'
,
'common/js/spec_helpers/discussion_spec_helper'
,
'discussion/js/views/discussion_board_view'
],
function
(
_
,
$
,
constants
,
Discussion
,
DiscussionSpecHelper
,
DiscussionBoardView
)
{
describe
(
'DiscussionBoardView'
,
function
()
{
var
createDiscussionBoardView
;
createDiscussionBoardView
=
function
()
{
var
discussionBoardView
,
discussion
=
DiscussionSpecHelper
.
createTestDiscussion
({}),
courseSettings
=
DiscussionSpecHelper
.
createTestCourseSettings
();
setFixtures
(
'<div class="discussion-board"><div class="forum-search"></div></div>'
);
DiscussionSpecHelper
.
setUnderscoreFixtures
();
discussionBoardView
=
new
DiscussionBoardView
({
el
:
$
(
'.discussion-board'
),
discussion
:
discussion
,
courseSettings
:
courseSettings
});
return
discussionBoardView
;
};
describe
(
'Search events'
,
function
()
{
it
(
'perform search when enter pressed inside search textfield'
,
function
()
{
var
discussionBoardView
=
createDiscussionBoardView
(),
threadListView
;
discussionBoardView
.
render
();
threadListView
=
discussionBoardView
.
discussionThreadListView
;
spyOn
(
threadListView
,
'performSearch'
);
discussionBoardView
.
$
(
'.search-input'
).
trigger
(
$
.
Event
(
'keydown'
,
{
which
:
constants
.
keyCodes
.
enter
}));
expect
(
threadListView
.
performSearch
).
toHaveBeenCalled
();
});
it
(
'perform search when search icon is clicked'
,
function
()
{
var
discussionBoardView
=
createDiscussionBoardView
(),
threadListView
;
discussionBoardView
.
render
();
threadListView
=
discussionBoardView
.
discussionThreadListView
;
spyOn
(
threadListView
,
'performSearch'
);
discussionBoardView
.
$el
.
find
(
'.search-btn'
).
click
();
expect
(
threadListView
.
performSearch
).
toHaveBeenCalled
();
});
});
});
});
}).
call
(
this
,
define
||
RequireJS
.
define
);
lms/djangoapps/discussion/static/discussion/js/spec/views/discussion_search_view_spec.js
deleted
100644 → 0
View file @
e5a57e75
define
([
'jquery'
,
'edx-ui-toolkit/js/utils/constants'
,
'discussion/js/views/discussion_search_view'
],
function
(
$
,
constants
,
DiscussionSearchView
)
{
'use strict'
;
describe
(
'DiscussionSearchView'
,
function
()
{
var
view
;
beforeEach
(
function
()
{
setFixtures
(
'<div class="search-container"></div>'
);
view
=
new
DiscussionSearchView
({
el
:
$
(
'.search-container'
),
threadListView
:
{
performSearch
:
jasmine
.
createSpy
()
}
}).
render
();
});
describe
(
'Search events'
,
function
()
{
it
(
'perform search when enter pressed inside search textfield'
,
function
()
{
view
.
$el
.
find
(
'.search-input'
).
trigger
(
$
.
Event
(
'keydown'
,
{
which
:
constants
.
keyCodes
.
enter
}));
expect
(
view
.
threadListView
.
performSearch
).
toHaveBeenCalled
();
});
it
(
'perform search when search icon is clicked'
,
function
()
{
view
.
$el
.
find
(
'.search-btn'
).
click
();
expect
(
view
.
threadListView
.
performSearch
).
toHaveBeenCalled
();
});
});
});
}
);
lms/djangoapps/discussion/static/discussion/js/views/discussion_board_view.js
0 → 100644
View file @
57fa123f
/* globals Discussion */
(
function
(
define
)
{
'use strict'
;
define
([
'underscore'
,
'backbone'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/constants'
,
'common/js/discussion/utils'
,
'common/js/discussion/views/discussion_thread_list_view'
,
'discussion/js/views/discussion_fake_breadcrumbs'
,
'discussion/js/views/discussion_search_view'
,
'text!discussion/templates/discussion-home.underscore'
],
function
(
_
,
Backbone
,
HtmlUtils
,
Constants
,
DiscussionUtil
,
DiscussionThreadListView
,
DiscussionFakeBreadcrumbs
,
DiscussionSearchView
,
discussionHomeTemplate
)
{
var
DiscussionBoardView
=
Backbone
.
View
.
extend
({
events
:
{
'click .forum-nav-browse-title'
:
'selectTopicHandler'
,
'click .all-topics'
:
'toggleBrowseMenu'
,
'keypress .forum-nav-browse-filter-input'
:
function
(
event
)
{
return
DiscussionUtil
.
ignoreEnterKey
(
event
);
},
'keyup .forum-nav-browse-filter-input'
:
'filterTopics'
,
'keydown .forum-nav-browse-filter-input'
:
'keyboardBinding'
,
'click .forum-nav-browse-menu-wrapper'
:
'ignoreClick'
,
'keydown .search-input'
:
'performSearch'
,
'click .search-btn'
:
'performSearch'
,
'topic:selected'
:
'clearSearch'
},
initialize
:
function
(
options
)
{
this
.
courseSettings
=
options
.
courseSettings
;
this
.
sidebar_padding
=
10
;
this
.
current_search
=
''
;
this
.
mode
=
'all'
;
this
.
discussion
=
options
.
discussion
;
this
.
filterInputReset
();
this
.
selectedTopic
=
$
(
'.forum-nav-browse-menu-item:visible .forum-nav-browse-title.is-focused'
);
this
.
listenTo
(
this
.
model
,
'change'
,
this
.
render
);
},
render
:
function
()
{
this
.
discussionThreadListView
=
new
DiscussionThreadListView
({
collection
:
this
.
discussion
,
el
:
this
.
$
(
'.discussion-thread-list-container'
),
courseSettings
:
this
.
courseSettings
}).
render
();
this
.
searchView
=
new
DiscussionSearchView
({
el
:
this
.
$
(
'.forum-search'
)
}).
render
();
this
.
renderBreadcrumbs
();
$
(
window
).
bind
(
'load scroll resize'
,
this
.
updateSidebar
);
this
.
showBrowseMenu
(
true
);
return
this
;
},
renderBreadcrumbs
:
function
()
{
var
BreadcrumbsModel
=
Backbone
.
Model
.
extend
({
defaults
:
{
contents
:
[]
}
});
this
.
breadcrumbs
=
new
DiscussionFakeBreadcrumbs
({
el
:
$
(
'.has-breadcrumbs'
),
model
:
new
BreadcrumbsModel
(),
events
:
{
'click .all-topics'
:
function
(
event
)
{
event
.
preventDefault
();
}
}
}).
render
();
},
isBrowseMenuVisible
:
function
()
{
return
this
.
$
(
'.forum-nav-browse-menu-wrapper'
).
is
(
':visible'
);
},
showBrowseMenu
:
function
(
initialLoad
)
{
if
(
!
this
.
isBrowseMenuVisible
())
{
this
.
$
(
'.forum-nav-browse-menu-wrapper'
).
show
();
this
.
$
(
'.forum-nav-thread-list-wrapper'
).
hide
();
if
(
!
initialLoad
)
{
$
(
'.forum-nav-browse-filter-input'
).
focus
();
this
.
filterInputReset
();
}
this
.
updateSidebar
();
}
},
hideBrowseMenu
:
function
()
{
var
selectedTopicList
=
this
.
$
(
'.forum-nav-browse-title.is-focused'
);
if
(
this
.
isBrowseMenuVisible
())
{
selectedTopicList
.
removeClass
(
'is-focused'
);
this
.
$
(
'.forum-nav-browse-menu-wrapper'
).
hide
();
this
.
$
(
'.forum-nav-thread-list-wrapper'
).
show
();
if
(
this
.
selectedTopicId
!==
'undefined'
)
{
this
.
$
(
'.forum-nav-browse-filter-input'
).
attr
(
'aria-activedescendant'
,
this
.
selectedTopicId
);
}
this
.
updateSidebar
();
}
},
toggleBrowseMenu
:
function
(
event
)
{
var
inputText
=
this
.
$
(
'.forum-nav-browse-filter-input'
).
val
();
event
.
preventDefault
();
event
.
stopPropagation
();
if
(
this
.
isBrowseMenuVisible
())
{
this
.
hideBrowseMenu
();
}
else
{
if
(
inputText
!==
''
)
{
this
.
filterTopics
(
inputText
);
}
this
.
showBrowseMenu
();
}
this
.
breadcrumbs
.
model
.
set
(
'contents'
,
[]);
this
.
clearSearch
();
},
performSearch
:
function
(
event
)
{
if
(
event
.
which
===
Constants
.
keyCodes
.
enter
||
event
.
type
===
'click'
)
{
event
.
preventDefault
();
this
.
hideBrowseMenu
();
this
.
breadcrumbs
.
model
.
set
(
'contents'
,
[
'Search Results'
]);
this
.
discussionThreadListView
.
performSearch
(
$
(
'.search-input'
,
this
.
$el
));
}
},
clearSearch
:
function
()
{
this
.
$
(
'.search-input'
).
val
(
''
);
this
.
discussionThreadListView
.
clearSearchAlerts
();
},
updateSidebar
:
function
()
{
var
amount
,
browseFilterHeight
,
discussionBottomOffset
,
discussionsBodyBottom
,
discussionsBodyTop
,
headerHeight
,
refineBarHeight
,
scrollTop
,
sidebarHeight
,
topOffset
,
windowHeight
,
$discussionBody
,
$sidebar
;
scrollTop
=
$
(
window
).
scrollTop
();
windowHeight
=
$
(
window
).
height
();
$discussionBody
=
this
.
$
(
'.discussion-column'
);
discussionsBodyTop
=
$discussionBody
[
0
]
?
$discussionBody
.
offset
().
top
:
undefined
;
discussionsBodyBottom
=
discussionsBodyTop
+
$discussionBody
.
outerHeight
();
$sidebar
=
this
.
$
(
'.forum-nav'
);
if
(
scrollTop
>
discussionsBodyTop
-
this
.
sidebar_padding
)
{
$sidebar
.
css
(
'top'
,
scrollTop
-
discussionsBodyTop
+
this
.
sidebar_padding
);
}
else
{
$sidebar
.
css
(
'top'
,
'0'
);
}
sidebarHeight
=
windowHeight
-
Math
.
max
(
discussionsBodyTop
-
scrollTop
,
this
.
sidebar_padding
);
topOffset
=
scrollTop
+
windowHeight
;
discussionBottomOffset
=
discussionsBodyBottom
+
this
.
sidebar_padding
;
amount
=
Math
.
max
(
topOffset
-
discussionBottomOffset
,
0
);
sidebarHeight
=
sidebarHeight
-
this
.
sidebar_padding
-
amount
;
sidebarHeight
=
Math
.
min
(
sidebarHeight
+
1
,
$discussionBody
.
outerHeight
());
$sidebar
.
css
(
'height'
,
sidebarHeight
);
headerHeight
=
this
.
$
(
'.forum-nav-header'
).
outerHeight
();
refineBarHeight
=
this
.
$
(
'.forum-nav-refine-bar'
).
outerHeight
();
browseFilterHeight
=
this
.
$
(
'.forum-nav-browse-filter'
).
outerHeight
();
this
.
$
(
'.forum-nav-thread-list'
)
.
css
(
'height'
,
(
sidebarHeight
-
headerHeight
-
refineBarHeight
-
2
)
+
'px'
);
this
.
$
(
'.forum-nav-browse-menu'
)
.
css
(
'height'
,
(
sidebarHeight
-
headerHeight
-
browseFilterHeight
-
2
)
+
'px'
);
},
goHome
:
function
()
{
var
url
=
DiscussionUtil
.
urlFor
(
'notifications_status'
,
window
.
user
.
get
(
'id'
));
HtmlUtils
.
append
(
this
.
$
(
'.forum-content'
).
empty
(),
HtmlUtils
.
template
(
discussionHomeTemplate
)({}));
this
.
$
(
'.forum-nav-thread-list a'
).
removeClass
(
'is-active'
).
find
(
'.sr'
)
.
remove
();
this
.
$
(
'input.email-setting'
).
bind
(
'click'
,
this
.
updateEmailNotifications
);
DiscussionUtil
.
safeAjax
({
url
:
url
,
type
:
'GET'
,
success
:
function
(
response
)
{
$
(
'input.email-setting'
).
prop
(
'checked'
,
response
.
status
);
}
});
},
filterInputReset
:
function
()
{
this
.
filterEnabled
=
true
;
this
.
selectedTopicIndex
=
-
1
;
this
.
selectedTopicId
=
null
;
},
selectOption
:
function
(
element
)
{
var
activeDescendantId
,
activeDescendantText
;
if
(
this
.
selectedTopic
.
length
>
0
)
{
this
.
selectedTopic
.
removeClass
(
'is-focused'
);
}
if
(
element
)
{
element
.
addClass
(
'is-focused'
);
activeDescendantId
=
element
.
parent
().
attr
(
'id'
);
activeDescendantText
=
element
.
text
();
this
.
selectedTopic
=
element
;
this
.
selectedTopicId
=
activeDescendantId
;
this
.
$
(
'.forum-nav-browse-filter-input'
)
.
attr
(
'aria-activedescendant'
,
activeDescendantId
)
.
val
(
activeDescendantText
);
}
},
keyboardBinding
:
function
(
event
)
{
var
key
=
event
.
which
,
$inputText
=
$
(
'.forum-nav-browse-filter-input'
),
$filteredMenuItems
=
$
(
'.forum-nav-browse-menu-item:visible'
),
filteredMenuItemsLen
=
$filteredMenuItems
.
length
,
$curOption
=
$filteredMenuItems
.
eq
(
0
).
find
(
'.forum-nav-browse-title'
).
eq
(
0
),
$activeOption
,
$prev
,
$next
;
switch
(
key
)
{
case
Constants
.
keyCodes
.
enter
:
$activeOption
=
$filteredMenuItems
.
find
(
'.forum-nav-browse-title.is-focused'
);
if
(
$inputText
.
val
()
!==
''
)
{
$activeOption
.
trigger
(
'click'
);
this
.
filterInputReset
();
}
break
;
case
Constants
.
keyCodes
.
esc
:
this
.
toggleBrowseMenu
(
event
);
this
.
$
(
'.forum-nav-browse-filter-input'
).
val
(
''
);
this
.
filterInputReset
();
$
(
'.all-topics'
).
trigger
(
'click'
);
break
;
case
Constants
.
keyCodes
.
up
:
if
(
this
.
selectedTopicIndex
>
0
)
{
this
.
selectedTopicIndex
-=
1
;
if
(
this
.
isBrowseMenuVisible
())
{
$prev
=
$
(
'.forum-nav-browse-menu-item:visible'
)
.
eq
(
this
.
selectedTopicIndex
).
find
(
'.forum-nav-browse-title'
)
.
eq
(
0
);
this
.
filterEnabled
=
false
;
$curOption
.
removeClass
(
'is-focused'
);
$prev
.
addClass
(
'is-focused'
);
}
this
.
selectOption
(
$prev
);
}
break
;
case
Constants
.
keyCodes
.
down
:
if
(
this
.
selectedTopicIndex
<
filteredMenuItemsLen
-
1
)
{
this
.
selectedTopicIndex
+=
1
;
if
(
this
.
isBrowseMenuVisible
())
{
$next
=
$
(
'.forum-nav-browse-menu-item:visible'
)
.
eq
(
this
.
selectedTopicIndex
).
find
(
'.forum-nav-browse-title'
)
.
eq
(
0
);
this
.
filterEnabled
=
false
;
$curOption
.
removeClass
(
'is-focused'
);
$next
.
addClass
(
'is-focused'
);
}
this
.
selectOption
(
$next
);
}
break
;
default
:
}
},
filterTopics
:
function
()
{
var
$items
,
query
,
filteredItems
,
self
=
this
;
query
=
this
.
$
(
'.forum-nav-browse-filter-input'
).
val
();
$items
=
this
.
$
(
'.forum-nav-browse-menu-item'
);
if
(
query
.
length
===
0
)
{
$items
.
find
(
'.forum-nav-browse-title.is-focused'
).
removeClass
(
'is-focused'
);
return
$items
.
show
();
}
else
{
if
(
self
.
filterEnabled
)
{
$items
.
hide
();
filteredItems
=
$items
.
each
(
function
(
i
,
item
)
{
var
path
,
pathText
,
$item
=
$
(
item
);
if
(
!
$item
.
is
(
':visible'
))
{
pathText
=
self
.
getPathText
(
$item
).
toLowerCase
();
if
(
query
.
split
(
' '
).
every
(
function
(
term
)
{
return
pathText
.
search
(
term
.
toLowerCase
())
!==
-
1
;
}))
{
path
=
$item
.
parents
(
'.forum-nav-browse-menu-item'
).
andSelf
();
path
.
add
(
$item
.
find
(
'.forum-nav-browse-menu-item'
)).
show
();
}
}
});
}
return
filteredItems
;
}
},
getPathText
:
function
(
item
)
{
var
path
,
pathTitles
;
path
=
item
.
parents
(
'.forum-nav-browse-menu-item'
).
andSelf
();
pathTitles
=
path
.
children
(
'.forum-nav-browse-title'
).
map
(
function
(
i
,
elem
)
{
return
$
(
elem
).
text
();
}).
get
();
return
pathTitles
.
join
(
' / '
);
},
selectTopicHandler
:
function
(
event
)
{
var
$item
=
$
(
event
.
target
).
closest
(
'.forum-nav-browse-menu-item'
);
event
.
preventDefault
();
this
.
hideBrowseMenu
();
this
.
trigger
(
'topic:selected'
,
this
.
getBreadcrumbText
(
$item
));
return
this
.
discussionThreadListView
.
selectTopic
(
$
(
event
.
target
));
},
getBreadcrumbText
:
function
(
$item
)
{
var
$parentSubMenus
=
$item
.
parents
(
'.forum-nav-browse-submenu'
),
crumbs
=
[],
subTopic
=
$
(
'.forum-nav-browse-title'
,
$item
)
.
first
()
.
text
()
.
trim
();
$parentSubMenus
.
each
(
function
(
i
,
el
)
{
crumbs
.
push
(
$
(
el
).
siblings
(
'.forum-nav-browse-title'
)
.
first
()
.
text
()
.
trim
()
);
});
if
(
subTopic
!==
'All Discussions'
)
{
crumbs
.
push
(
subTopic
);
}
return
crumbs
;
}
});
return
DiscussionBoardView
;
});
}).
call
(
this
,
define
||
RequireJS
.
define
);
lms/djangoapps/discussion/static/discussion/js/views/discussion_search_view.js
View file @
57fa123f
...
...
@@ -15,33 +15,16 @@
* in order to clean up that file and make it possible to break its logic into files like this one.
*/
var
searchView
=
Backbone
.
View
.
extend
({
events
:
{
'keydown .search-input'
:
'performSearch'
,
'click .search-btn'
:
'performSearch'
,
'topic:selected'
:
'clearSearch'
},
initialize
:
function
(
options
)
{
_
.
extend
(
this
,
_
.
pick
(
options
,
'threadListView'
));
_
.
extend
(
this
,
_
.
pick
(
options
,
[
'discussionBoardView'
]
));
this
.
template
=
HtmlUtils
.
template
(
searchTemplate
);
this
.
threadListView
=
options
.
threadListView
;
this
.
listenTo
(
this
.
model
,
'change'
,
this
.
render
);
this
.
render
();
},
render
:
function
()
{
HtmlUtils
.
setHtml
(
this
.
$el
,
this
.
template
());
return
this
;
},
performSearch
:
function
(
event
)
{
if
(
event
.
which
===
constants
.
keyCodes
.
enter
||
event
.
type
===
'click'
)
{
event
.
preventDefault
();
this
.
threadListView
.
performSearch
(
$
(
'.search-input'
,
this
.
$el
));
}
},
clearSearch
:
function
()
{
this
.
$
(
'.search-input'
).
val
(
''
);
this
.
threadListView
.
clearSearchAlerts
();
}
});
...
...
common/static/common/templates/discussion
/discussion-home.underscore
→
lms/djangoapps/discussion/static/discussion/templates
/discussion-home.underscore
View file @
57fa123f
File moved
lms/djangoapps/discussion/templates/discussion/discussion_board.html
View file @
57fa123f
...
...
@@ -77,6 +77,8 @@ DiscussionBoardFactory({
<div
class=
"page-content"
>
<div
class=
"discussion-body layout layout-1t2t"
>
<aside
class=
"forum-nav layout-col layout-col-a"
role=
"complementary"
aria-label=
"${_("
Discussion
thread
list
")}"
>
<
%
include
file=
"_filter_dropdown.html"
/>
<div
class=
"discussion-thread-list-container"
></div>
</aside>
<main
id=
"main"
aria-label=
"Content"
tabindex=
"-1"
class=
"discussion-column layout-col layout-col-b"
>
...
...
lms/static/lms/js/spec/main.js
View file @
57fa123f
...
...
@@ -288,11 +288,11 @@
deps
:
[
'jquery'
,
'underscore'
,
'slick.core'
,
'slick.grid'
],
init
:
function
()
{
// Set global variables that the util code is expecting to be defined
require
([
require
([
// eslint-disable-line global-require
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
],
function
(
HtmlUtils
,
StringUtils
)
{
window
.
edx
=
edx
||
{};
window
.
edx
=
window
.
edx
||
{};
window
.
edx
.
HtmlUtils
=
HtmlUtils
;
window
.
edx
.
StringUtils
=
StringUtils
;
});
...
...
@@ -383,7 +383,7 @@
deps
:
[
'jquery'
,
'underscore'
,
'underscore.string'
,
'backbone'
,
'gettext'
],
init
:
function
()
{
// Set global variables that the payment code is expecting to be defined
require
([
require
([
// eslint-disable-line global-require
'underscore'
,
'underscore.string'
,
'edx-ui-toolkit/js/utils/html-utils'
,
...
...
@@ -391,7 +391,7 @@
],
function
(
_
,
str
,
HtmlUtils
,
StringUtils
)
{
window
.
_
=
_
;
window
.
_
.
str
=
str
;
window
.
edx
=
edx
||
{};
window
.
edx
=
window
.
edx
||
{};
window
.
edx
.
HtmlUtils
=
HtmlUtils
;
window
.
edx
.
StringUtils
=
StringUtils
;
});
...
...
@@ -527,10 +527,21 @@
exports
:
'DiscussionUtil'
,
init
:
function
()
{
// Set global variables that the discussion code is expecting to be defined
require
([
'backbone'
,
'URI'
],
function
(
Backbone
,
URI
)
{
window
.
Backbone
=
Backbone
;
window
.
URI
=
URI
;
});
require
(
// eslint-disable-line global-require
[
'backbone'
,
'URI'
,
'edx-ui-toolkit/js/utils/html-utils'
,
'edx-ui-toolkit/js/utils/string-utils'
],
function
(
Backbone
,
URI
,
HtmlUtils
,
StringUtils
)
{
window
.
Backbone
=
Backbone
;
window
.
URI
=
URI
;
window
.
edx
=
window
.
edx
||
{};
window
.
edx
.
HtmlUtils
=
HtmlUtils
;
window
.
edx
.
StringUtils
=
StringUtils
;
}
);
}
},
'common/js/discussion/content'
:
{
...
...
@@ -542,11 +553,11 @@
'common/js/discussion/discussion'
:
{
deps
:
[
'common/js/discussion/utils'
,
'
xmodule_js/common_static/
common/js/discussion/content'
'common/js/discussion/content'
],
exports
:
'Discussion'
},
'common/js/discussion/discussion_course_settings'
:
{
'common/js/discussion/
models/
discussion_course_settings'
:
{
deps
:
[
'common/js/discussion/utils'
],
...
...
@@ -664,7 +675,7 @@
var
testFiles
=
[
'discussion/js/spec/discussion_board_factory_spec.js'
,
'discussion/js/spec/discussion_profile_page_factory_spec.js'
,
'discussion/js/spec/
views/discussion_search
_view_spec.js'
,
'discussion/js/spec/
discussion_board
_view_spec.js'
,
'discussion/js/spec/views/discussion_user_profile_view_spec.js'
,
'lms/js/spec/preview/preview_factory_spec.js'
,
'js/spec/api_admin/catalog_preview_spec.js'
,
...
...
lms/templates/discussion/_js_body_dependencies.html
View file @
57fa123f
...
...
@@ -16,11 +16,14 @@ from openedx.core.djangolib.js_utils import js_escaped_string
<
%
discussion_classes =
[
['
Discussion
',
'
common
/
js
/
discussion
/
discussion
'],
['
Content
',
'
common
/
js
/
discussion
/
content
'],
['
DiscussionModuleView
',
'
common
/
js
/
discussion
/
discussion_module_view
'],
['
DiscussionThreadView
',
'
common
/
js
/
discussion
/
views
/
discussion_thread_view
'],
['
DiscussionThreadListView
',
'
common
/
js
/
discussion
/
views
/
discussion_thread_list_view
'],
['
DiscussionThreadProfileView
',
'
common
/
js
/
discussion
/
views
/
discussion_thread_profile_view
'],
['
DiscussionUtil
',
'
common
/
js
/
discussion
/
utils
'],
['
DiscussionCourseSettings
',
'
common
/
js
/
discussion
/
models
/
discussion_course_settings
'],
['
DiscussionUser
',
'
common
/
js
/
discussion
/
models
/
discussion_user
'],
['
NewPostView
',
'
common
/
js
/
discussion
/
views
/
new_post_view
'],
]
%
>
...
...
lms/templates/discussion/_thread_list_template.html
View file @
57fa123f
<
%
page
expression_filter=
"h"
/>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<script
type=
"text/template"
id=
"thread-list-template"
>
<%
include
file
=
"_filter_dropdown.html"
/>
<
div
class
=
"forum-nav-thread-list-wrapper"
id
=
"sort-filter-wrapper"
tabindex
=
"-1"
>
<
div
class
=
"forum-nav-thread-list-wrapper"
id
=
"sort-filter-wrapper"
tabindex
=
"-1"
style
=
"display:none"
>
<
div
class
=
"forum-nav-refine-bar"
>
<
label
class
=
"forum-nav-filter-main"
>
##
Translators
:
This
labels
a
filter
menu
in
forum
navigation
...
...
lms/templates/discussion/_underscore_templates.html
View file @
57fa123f
...
...
@@ -14,7 +14,7 @@
<
%
template_names =
[
'
thread
',
'
thread-show
',
'
thread-edit
',
'
thread-response
',
'
thread-response-show
',
'
thread-response-edit
',
'
response-comment-show
',
'
response-comment-edit
',
'
thread-list-item
',
'
discussion-home
',
'
search-alert
',
'
response-comment-show
',
'
response-comment-edit
',
'
thread-list-item
',
'
search-alert
',
'
new-post
',
'
new-post-menu-entry
',
'
new-post-menu-category
',
'
new-post-alert
',
'
topic
',
'
post-user-display
',
'
inline-discussion
',
'
pagination
',
'
profile-thread
',
'
customwmd-prompt
',
'
nav-loading
',
'
thread-type
'
]
...
...
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