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
b92a180d
Commit
b92a180d
authored
Jul 29, 2012
by
Rocky Duan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add tags to threads & view threads by tags
parent
1ad838ac
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
442 additions
and
14 deletions
+442
-14
common/static/js/vendor/jquery.tagsinput.js
+354
-0
lms/djangoapps/django_comment_client/base/urls.py
+2
-0
lms/djangoapps/django_comment_client/base/views.py
+8
-3
lms/djangoapps/django_comment_client/forum/views.py
+14
-1
lms/lib/comment_client.py
+4
-4
lms/static/coffee/src/customwmd.coffee
+8
-2
lms/static/coffee/src/discussion.coffee
+15
-3
lms/static/css/vendor/jquery.tagsinput.css
+7
-0
lms/static/sass/_discussion.scss
+17
-0
lms/templates/discussion/index.html
+2
-0
lms/templates/discussion/inline.html
+1
-1
lms/templates/discussion/thread.html
+10
-0
No files found.
common/static/js/vendor/jquery.tagsinput.js
0 → 100644
View file @
b92a180d
/*
jQuery Tags Input Plugin 1.3.3
Copyright (c) 2011 XOXCO, Inc
Documentation for this plugin lives here:
http://xoxco.com/clickable/jquery-tags-input
Licensed under the MIT license:
http://www.opensource.org/licenses/mit-license.php
ben@xoxco.com
*/
(
function
(
$
)
{
var
delimiter
=
new
Array
();
var
tags_callbacks
=
new
Array
();
$
.
fn
.
doAutosize
=
function
(
o
){
var
minWidth
=
$
(
this
).
data
(
'minwidth'
),
maxWidth
=
$
(
this
).
data
(
'maxwidth'
),
val
=
''
,
input
=
$
(
this
),
testSubject
=
$
(
'#'
+
$
(
this
).
data
(
'tester_id'
));
if
(
val
===
(
val
=
input
.
val
()))
{
return
;}
// Enter new content into testSubject
var
escaped
=
val
.
replace
(
/&/g
,
'&'
).
replace
(
/
\s
/g
,
' '
).
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
);
testSubject
.
html
(
escaped
);
// Calculate new width + whether to change
var
testerWidth
=
testSubject
.
width
(),
newWidth
=
(
testerWidth
+
o
.
comfortZone
)
>=
minWidth
?
testerWidth
+
o
.
comfortZone
:
minWidth
,
currentWidth
=
input
.
width
(),
isValidWidthChange
=
(
newWidth
<
currentWidth
&&
newWidth
>=
minWidth
)
||
(
newWidth
>
minWidth
&&
newWidth
<
maxWidth
);
// Animate width
if
(
isValidWidthChange
)
{
input
.
width
(
newWidth
);
}
};
$
.
fn
.
resetAutosize
=
function
(
options
){
// alert(JSON.stringify(options));
var
minWidth
=
$
(
this
).
data
(
'minwidth'
)
||
options
.
minInputWidth
||
$
(
this
).
width
(),
maxWidth
=
$
(
this
).
data
(
'maxwidth'
)
||
options
.
maxInputWidth
||
(
$
(
this
).
closest
(
'.tagsinput'
).
width
()
-
options
.
inputPadding
),
val
=
''
,
input
=
$
(
this
),
testSubject
=
$
(
'<tester/>'
).
css
({
position
:
'absolute'
,
top
:
-
9999
,
left
:
-
9999
,
width
:
'auto'
,
fontSize
:
input
.
css
(
'fontSize'
),
fontFamily
:
input
.
css
(
'fontFamily'
),
fontWeight
:
input
.
css
(
'fontWeight'
),
letterSpacing
:
input
.
css
(
'letterSpacing'
),
whiteSpace
:
'nowrap'
}),
testerId
=
$
(
this
).
attr
(
'id'
)
+
'_autosize_tester'
;
if
(
!
$
(
'#'
+
testerId
).
length
>
0
){
testSubject
.
attr
(
'id'
,
testerId
);
testSubject
.
appendTo
(
'body'
);
}
input
.
data
(
'minwidth'
,
minWidth
);
input
.
data
(
'maxwidth'
,
maxWidth
);
input
.
data
(
'tester_id'
,
testerId
);
input
.
css
(
'width'
,
minWidth
);
};
$
.
fn
.
addTag
=
function
(
value
,
options
)
{
options
=
jQuery
.
extend
({
focus
:
false
,
callback
:
true
},
options
);
this
.
each
(
function
()
{
var
id
=
$
(
this
).
attr
(
'id'
);
var
tagslist
=
$
(
this
).
val
().
split
(
delimiter
[
id
]);
if
(
tagslist
[
0
]
==
''
)
{
tagslist
=
new
Array
();
}
value
=
jQuery
.
trim
(
value
);
if
(
options
.
unique
)
{
var
skipTag
=
$
(
this
).
tagExist
(
value
);
if
(
skipTag
==
true
)
{
//Marks fake input as not_valid to let styling it
$
(
'#'
+
id
+
'_tag'
).
addClass
(
'not_valid'
);
}
}
else
{
var
skipTag
=
false
;
}
if
(
value
!=
''
&&
skipTag
!=
true
)
{
$
(
'<span>'
).
addClass
(
'tag'
).
append
(
$
(
'<span>'
).
text
(
value
).
append
(
' '
),
$
(
'<a>'
,
{
href
:
'#'
,
title
:
'Removing tag'
,
text
:
'x'
}).
click
(
function
()
{
return
$
(
'#'
+
id
).
removeTag
(
escape
(
value
));
})
).
insertBefore
(
'#'
+
id
+
'_addTag'
);
tagslist
.
push
(
value
);
$
(
'#'
+
id
+
'_tag'
).
val
(
''
);
if
(
options
.
focus
)
{
$
(
'#'
+
id
+
'_tag'
).
focus
();
}
else
{
$
(
'#'
+
id
+
'_tag'
).
blur
();
}
$
.
fn
.
tagsInput
.
updateTagsField
(
this
,
tagslist
);
if
(
options
.
callback
&&
tags_callbacks
[
id
]
&&
tags_callbacks
[
id
][
'onAddTag'
])
{
var
f
=
tags_callbacks
[
id
][
'onAddTag'
];
f
.
call
(
this
,
value
);
}
if
(
tags_callbacks
[
id
]
&&
tags_callbacks
[
id
][
'onChange'
])
{
var
i
=
tagslist
.
length
;
var
f
=
tags_callbacks
[
id
][
'onChange'
];
f
.
call
(
this
,
$
(
this
),
tagslist
[
i
-
1
]);
}
}
});
return
false
;
};
$
.
fn
.
removeTag
=
function
(
value
)
{
value
=
unescape
(
value
);
this
.
each
(
function
()
{
var
id
=
$
(
this
).
attr
(
'id'
);
var
old
=
$
(
this
).
val
().
split
(
delimiter
[
id
]);
$
(
'#'
+
id
+
'_tagsinput .tag'
).
remove
();
str
=
''
;
for
(
i
=
0
;
i
<
old
.
length
;
i
++
)
{
if
(
old
[
i
]
!=
value
)
{
str
=
str
+
delimiter
[
id
]
+
old
[
i
];
}
}
$
.
fn
.
tagsInput
.
importTags
(
this
,
str
);
if
(
tags_callbacks
[
id
]
&&
tags_callbacks
[
id
][
'onRemoveTag'
])
{
var
f
=
tags_callbacks
[
id
][
'onRemoveTag'
];
f
.
call
(
this
,
value
);
}
});
return
false
;
};
$
.
fn
.
tagExist
=
function
(
val
)
{
var
id
=
$
(
this
).
attr
(
'id'
);
var
tagslist
=
$
(
this
).
val
().
split
(
delimiter
[
id
]);
return
(
jQuery
.
inArray
(
val
,
tagslist
)
>=
0
);
//true when tag exists, false when not
};
// clear all existing tags and import new ones from a string
$
.
fn
.
importTags
=
function
(
str
)
{
id
=
$
(
this
).
attr
(
'id'
);
$
(
'#'
+
id
+
'_tagsinput .tag'
).
remove
();
$
.
fn
.
tagsInput
.
importTags
(
this
,
str
);
}
$
.
fn
.
tagsInput
=
function
(
options
)
{
var
settings
=
jQuery
.
extend
({
interactive
:
true
,
defaultText
:
'add a tag'
,
minChars
:
0
,
width
:
'300px'
,
height
:
'100px'
,
autocomplete
:
{
selectFirst
:
false
},
'hide'
:
true
,
'delimiter'
:
','
,
'unique'
:
true
,
removeWithBackspace
:
true
,
placeholderColor
:
'#666666'
,
autosize
:
true
,
comfortZone
:
20
,
inputPadding
:
6
*
2
},
options
);
this
.
each
(
function
()
{
if
(
settings
.
hide
)
{
$
(
this
).
hide
();
}
var
id
=
$
(
this
).
attr
(
'id'
);
if
(
!
id
||
delimiter
[
$
(
this
).
attr
(
'id'
)])
{
id
=
$
(
this
).
attr
(
'id'
,
'tags'
+
new
Date
().
getTime
()).
attr
(
'id'
);
}
var
data
=
jQuery
.
extend
({
pid
:
id
,
real_input
:
'#'
+
id
,
holder
:
'#'
+
id
+
'_tagsinput'
,
input_wrapper
:
'#'
+
id
+
'_addTag'
,
fake_input
:
'#'
+
id
+
'_tag'
},
settings
);
delimiter
[
id
]
=
data
.
delimiter
;
if
(
settings
.
onAddTag
||
settings
.
onRemoveTag
||
settings
.
onChange
)
{
tags_callbacks
[
id
]
=
new
Array
();
tags_callbacks
[
id
][
'onAddTag'
]
=
settings
.
onAddTag
;
tags_callbacks
[
id
][
'onRemoveTag'
]
=
settings
.
onRemoveTag
;
tags_callbacks
[
id
][
'onChange'
]
=
settings
.
onChange
;
}
var
markup
=
'<div id="'
+
id
+
'_tagsinput" class="tagsinput"><div id="'
+
id
+
'_addTag">'
;
if
(
settings
.
interactive
)
{
markup
=
markup
+
'<input id="'
+
id
+
'_tag" value="" data-default="'
+
settings
.
defaultText
+
'" />'
;
}
markup
=
markup
+
'</div><div class="tags_clear"></div></div>'
;
$
(
markup
).
insertAfter
(
this
);
$
(
data
.
holder
).
css
(
'width'
,
settings
.
width
);
$
(
data
.
holder
).
css
(
'min-height'
,
settings
.
height
);
$
(
data
.
holder
).
css
(
'height'
,
'100%'
);
if
(
$
(
data
.
real_input
).
val
()
!=
''
)
{
$
.
fn
.
tagsInput
.
importTags
(
$
(
data
.
real_input
),
$
(
data
.
real_input
).
val
());
}
if
(
settings
.
interactive
)
{
$
(
data
.
fake_input
).
val
(
$
(
data
.
fake_input
).
attr
(
'data-default'
));
$
(
data
.
fake_input
).
css
(
'color'
,
settings
.
placeholderColor
);
$
(
data
.
fake_input
).
resetAutosize
(
settings
);
$
(
data
.
holder
).
bind
(
'click'
,
data
,
function
(
event
)
{
$
(
event
.
data
.
fake_input
).
focus
();
});
$
(
data
.
fake_input
).
bind
(
'focus'
,
data
,
function
(
event
)
{
if
(
$
(
event
.
data
.
fake_input
).
val
()
==
$
(
event
.
data
.
fake_input
).
attr
(
'data-default'
))
{
$
(
event
.
data
.
fake_input
).
val
(
''
);
}
$
(
event
.
data
.
fake_input
).
css
(
'color'
,
'#000000'
);
});
if
(
settings
.
autocomplete_url
!=
undefined
)
{
autocomplete_options
=
{
source
:
settings
.
autocomplete_url
};
for
(
attrname
in
settings
.
autocomplete
)
{
autocomplete_options
[
attrname
]
=
settings
.
autocomplete
[
attrname
];
}
if
(
jQuery
.
Autocompleter
!==
undefined
)
{
$
(
data
.
fake_input
).
autocomplete
(
settings
.
autocomplete_url
,
settings
.
autocomplete
);
$
(
data
.
fake_input
).
bind
(
'result'
,
data
,
function
(
event
,
data
,
formatted
)
{
if
(
data
)
{
$
(
'#'
+
id
).
addTag
(
data
[
0
]
+
""
,{
focus
:
true
,
unique
:(
settings
.
unique
)});
}
});
}
else
if
(
jQuery
.
ui
.
autocomplete
!==
undefined
)
{
$
(
data
.
fake_input
).
autocomplete
(
autocomplete_options
);
$
(
data
.
fake_input
).
bind
(
'autocompleteselect'
,
data
,
function
(
event
,
ui
)
{
$
(
event
.
data
.
real_input
).
addTag
(
ui
.
item
.
value
,{
focus
:
true
,
unique
:(
settings
.
unique
)});
return
false
;
});
}
}
else
{
// if a user tabs out of the field, create a new tag
// this is only available if autocomplete is not used.
$
(
data
.
fake_input
).
bind
(
'blur'
,
data
,
function
(
event
)
{
var
d
=
$
(
this
).
attr
(
'data-default'
);
if
(
$
(
event
.
data
.
fake_input
).
val
()
!=
''
&&
$
(
event
.
data
.
fake_input
).
val
()
!=
d
)
{
if
(
(
event
.
data
.
minChars
<=
$
(
event
.
data
.
fake_input
).
val
().
length
)
&&
(
!
event
.
data
.
maxChars
||
(
event
.
data
.
maxChars
>=
$
(
event
.
data
.
fake_input
).
val
().
length
))
)
$
(
event
.
data
.
real_input
).
addTag
(
$
(
event
.
data
.
fake_input
).
val
(),{
focus
:
true
,
unique
:(
settings
.
unique
)});
}
else
{
$
(
event
.
data
.
fake_input
).
val
(
$
(
event
.
data
.
fake_input
).
attr
(
'data-default'
));
$
(
event
.
data
.
fake_input
).
css
(
'color'
,
settings
.
placeholderColor
);
}
return
false
;
});
}
// if user types a comma, create a new tag
$
(
data
.
fake_input
).
bind
(
'keypress'
,
data
,
function
(
event
)
{
if
(
event
.
which
==
event
.
data
.
delimiter
.
charCodeAt
(
0
)
||
event
.
which
==
13
)
{
event
.
preventDefault
();
if
(
(
event
.
data
.
minChars
<=
$
(
event
.
data
.
fake_input
).
val
().
length
)
&&
(
!
event
.
data
.
maxChars
||
(
event
.
data
.
maxChars
>=
$
(
event
.
data
.
fake_input
).
val
().
length
))
)
$
(
event
.
data
.
real_input
).
addTag
(
$
(
event
.
data
.
fake_input
).
val
(),{
focus
:
true
,
unique
:(
settings
.
unique
)});
$
(
event
.
data
.
fake_input
).
resetAutosize
(
settings
);
return
false
;
}
else
if
(
event
.
data
.
autosize
)
{
$
(
event
.
data
.
fake_input
).
doAutosize
(
settings
);
}
});
//Delete last tag on backspace
data
.
removeWithBackspace
&&
$
(
data
.
fake_input
).
bind
(
'keydown'
,
function
(
event
)
{
if
(
event
.
keyCode
==
8
&&
$
(
this
).
val
()
==
''
)
{
event
.
preventDefault
();
var
last_tag
=
$
(
this
).
closest
(
'.tagsinput'
).
find
(
'.tag:last'
).
text
();
var
id
=
$
(
this
).
attr
(
'id'
).
replace
(
/_tag$/
,
''
);
last_tag
=
last_tag
.
replace
(
/
[\s]
+x$/
,
''
);
$
(
'#'
+
id
).
removeTag
(
escape
(
last_tag
));
$
(
this
).
trigger
(
'focus'
);
}
});
$
(
data
.
fake_input
).
blur
();
//Removes the not_valid class when user changes the value of the fake input
if
(
data
.
unique
)
{
$
(
data
.
fake_input
).
keydown
(
function
(
event
){
if
(
event
.
keyCode
==
8
||
String
.
fromCharCode
(
event
.
which
).
match
(
/
\w
+|
[
áéíóúÁÉÍÓÚñÑ,
/]
+/
))
{
$
(
this
).
removeClass
(
'not_valid'
);
}
});
}
}
// if settings.interactive
});
return
this
;
};
$
.
fn
.
tagsInput
.
updateTagsField
=
function
(
obj
,
tagslist
)
{
var
id
=
$
(
obj
).
attr
(
'id'
);
$
(
obj
).
val
(
tagslist
.
join
(
delimiter
[
id
]));
};
$
.
fn
.
tagsInput
.
importTags
=
function
(
obj
,
val
)
{
$
(
obj
).
val
(
''
);
var
id
=
$
(
obj
).
attr
(
'id'
);
var
tags
=
val
.
split
(
delimiter
[
id
]);
for
(
i
=
0
;
i
<
tags
.
length
;
i
++
)
{
$
(
obj
).
addTag
(
tags
[
i
],{
focus
:
false
,
callback
:
false
});
}
if
(
tags_callbacks
[
id
]
&&
tags_callbacks
[
id
][
'onChange'
])
{
var
f
=
tags_callbacks
[
id
][
'onChange'
];
f
.
call
(
obj
,
obj
,
tags
[
i
]);
}
};
})(
jQuery
);
lms/djangoapps/django_comment_client/base/urls.py
View file @
b92a180d
...
...
@@ -22,4 +22,6 @@ urlpatterns = patterns('django_comment_client.base.views',
url
(
r'(?P<commentable_id>[\w\-]+)/threads/create$'
,
'create_thread'
,
name
=
'create_thread'
),
url
(
r'(?P<commentable_id>[\w\-]+)/watch$'
,
'watch_commentable'
,
name
=
'watch_commentable'
),
url
(
r'(?P<commentable_id>[\w\-]+)/unwatch$'
,
'unwatch_commentable'
,
name
=
'unwatch_commentable'
),
url
(
r'search$'
,
'search'
,
name
=
'search'
),
)
lms/djangoapps/django_comment_client/base/views.py
View file @
b92a180d
...
...
@@ -65,7 +65,7 @@ def extract(dic, keys):
@login_required
@require_POST
def
create_thread
(
request
,
course_id
,
commentable_id
):
attributes
=
extract
(
request
.
POST
,
[
'body'
,
'title'
])
attributes
=
extract
(
request
.
POST
,
[
'body'
,
'title'
,
'tags'
])
attributes
[
'user_id'
]
=
request
.
user
.
id
attributes
[
'course_id'
]
=
course_id
response
=
comment_client
.
create_thread
(
commentable_id
,
attributes
)
...
...
@@ -75,7 +75,7 @@ def create_thread(request, course_id, commentable_id):
@login_required
@require_POST
def
update_thread
(
request
,
course_id
,
thread_id
):
attributes
=
extract
(
request
.
POST
,
[
'body'
,
'title'
])
attributes
=
extract
(
request
.
POST
,
[
'body'
,
'title'
,
'tags'
])
response
=
comment_client
.
update_thread
(
thread_id
,
attributes
)
return
JsonResponse
(
response
)
...
...
@@ -193,7 +193,12 @@ def unfollow(request, course_id, followed_user_id):
def
search
(
request
,
course_id
):
text
=
request
.
GET
.
get
(
'text'
,
None
)
commentable_id
=
request
.
GET
.
get
(
'commentable_id'
,
None
)
response
=
comment_client
.
search
(
text
,
commentable_id
)
tags
=
request
.
GET
.
get
(
'tags'
,
None
)
response
=
comment_client
.
search_threads
({
'text'
:
text
,
'commentable_id'
:
commentable_id
,
'tags'
:
tags
,
})
return
JsonResponse
(
response
)
@csrf.csrf_exempt
...
...
lms/djangoapps/django_comment_client/forum/views.py
View file @
b92a180d
...
...
@@ -101,8 +101,21 @@ def single_thread(request, course_id, thread_id):
def
search
(
request
,
course_id
):
course
=
check_course
(
course_id
)
text
=
request
.
GET
.
get
(
'text'
,
None
)
threads
=
comment_client
.
search
(
text
)
commentable_id
=
request
.
GET
.
get
(
'commentable_id'
,
None
)
tags
=
request
.
GET
.
get
(
'tags'
,
None
)
print
text
print
commentable_id
print
tags
threads
=
comment_client
.
search_threads
({
'text'
:
text
,
'commentable_id'
:
commentable_id
,
'tags'
:
tags
,
})
context
=
{
'csrf'
:
csrf
(
request
)[
'csrf_token'
],
'init'
:
''
,
...
...
lms/lib/comment_client.py
View file @
b92a180d
...
...
@@ -87,8 +87,8 @@ def unsubscribe_thread(user_id, thread_id, *args, **kwargs):
def
unsubscribe_commentable
(
user_id
,
commentable_id
,
*
args
,
**
kwargs
):
return
unsubscribe
(
user_id
,
{
'source_type'
:
'other'
,
'source_id'
:
commentable_id
})
def
search
(
text
,
commentable_id
=
None
,
*
args
,
**
kwargs
):
return
_perform_request
(
'get'
,
_url_for_search
(),
{
'text'
:
text
,
'commentable_id'
:
commentable_id
}
,
*
args
,
**
kwargs
)
def
search
_threads
(
attributes
,
*
args
,
**
kwargs
):
return
_perform_request
(
'get'
,
_url_for_search
_threads
(),
attributes
,
*
args
,
**
kwargs
)
def
_perform_request
(
method
,
url
,
data_or_params
=
None
,
*
args
,
**
kwargs
):
if
method
in
[
'post'
,
'put'
,
'patch'
]:
...
...
@@ -127,8 +127,8 @@ def _url_for_subscription(user_id):
def
_url_for_user
(
user_id
):
return
"{prefix}/users/{user_id}"
.
format
(
prefix
=
PREFIX
,
user_id
=
user_id
)
def
_url_for_search
():
return
"{prefix}/search"
.
format
(
prefix
=
PREFIX
)
def
_url_for_search
_threads
():
return
"{prefix}/search
/threads
"
.
format
(
prefix
=
PREFIX
)
def
_url_for_threads_tags
():
return
"{prefix}/threads/tags"
.
format
(
prefix
=
PREFIX
)
lms/static/coffee/src/customwmd.coffee
View file @
b92a180d
...
...
@@ -96,18 +96,24 @@ $ ->
deTilde
(
@
blocks
.
join
(
""
))
@
removeMathWrapper
:
(
_this
)
->
(
text
)
->
_this
.
removeMath
(
text
)
replaceMath
:
(
text
)
->
text
=
text
.
replace
/@@(\d+)@@/g
,
(
$0
,
$1
)
=>
@
math
[
$1
]
@
math
=
null
text
@
replaceMathWrapper
:
(
_this
)
->
(
text
)
->
_this
.
replaceMath
(
text
)
if
Markdown
?
Markdown
.
getMathCompatibleConverter
=
->
converter
=
Markdown
.
getSanitizingConverter
()
processor
=
new
MathJaxProcessor
()
converter
.
hooks
.
chain
"preConversion"
,
processor
.
removeMath
converter
.
hooks
.
chain
"postConversion"
,
processor
.
replaceMath
converter
.
hooks
.
chain
"preConversion"
,
MathJaxProcessor
.
removeMathWrapper
(
processor
)
#
processor.removeMath
converter
.
hooks
.
chain
"postConversion"
,
MathJaxProcessor
.
replaceMathWrapper
(
processor
)
#
.replaceMath
converter
Markdown
.
makeWmdEditor
=
(
elem
,
appended_id
,
imageUploadUrl
)
->
...
...
lms/static/coffee/src/discussion.coffee
View file @
b92a180d
...
...
@@ -111,6 +111,7 @@ Discussion =
Discussion
.
handleAnchorAndReload
(
response
)
,
'json'
if
id
in
$$user_info
.
subscribed_thread_ids
unwatchThread
=
generateDiscussionLink
(
"discussion-unwatch-thread"
,
"Unwatch"
,
handleUnwatchThread
)
$local
(
".info"
).
append
(
unwatchThread
)
...
...
@@ -118,11 +119,21 @@ Discussion =
watchThread
=
generateDiscussionLink
(
"discussion-watch-thread"
,
"Watch"
,
handleWatchThread
)
$local
(
".info"
).
append
(
watchThread
)
$local
=
generateLocal
(
discussion
)
if
$$user_info
?
$
(
discussion
).
find
(
".comment"
).
each
(
initializeVote
)
$
(
discussion
).
find
(
".thread"
).
each
(
initializeVote
).
each
(
initializeWatchThreads
)
$
local
(
".comment"
).
each
(
initializeVote
)
$
local
(
".thread"
).
each
(
initializeVote
).
each
(
initializeWatchThreads
)
initializeWatchDiscussion
(
discussion
)
if
$$tags
?
$local
(
".new-post-tags"
).
tagsInput
autocomplete
:
$$tags
interactive
:
true
defaultText
:
"add a tag"
height
:
"30px"
removeWithBackspace
:
true
bindContentEvents
:
(
content
)
->
$content
=
$
(
content
)
...
...
@@ -255,8 +266,9 @@ Discussion =
handleSubmitNewThread
=
(
elem
)
->
title
=
$local
(
".new-post-title"
).
val
()
body
=
$local
(
"#wmd-input-new-post-body-
#{
id
}
"
).
val
()
tags
=
$local
(
".new-post-tags"
).
val
()
url
=
Discussion
.
urlFor
(
'create_thread'
,
$local
(
".new-post-form"
).
attr
(
"_id"
))
$
.
post
url
,
{
title
:
title
,
body
:
body
},
(
response
,
textStatus
)
->
$
.
post
url
,
{
title
:
title
,
body
:
body
,
tags
:
tags
},
(
response
,
textStatus
)
->
if
textStatus
==
"success"
Discussion
.
handleAnchorAndReload
(
response
)
,
'json'
...
...
lms/static/css/vendor/jquery.tagsinput.css
0 → 100644
View file @
b92a180d
div
.tagsinput
{
border
:
1px
solid
#CCC
;
background
:
#FFF
;
padding
:
5px
;
width
:
300px
;
height
:
100px
;
overflow-y
:
auto
;}
div
.tagsinput
span
.tag
{
border
:
1px
solid
#a5d24a
;
-moz-border-radius
:
2px
;
-webkit-border-radius
:
2px
;
display
:
block
;
float
:
left
;
padding
:
5px
;
text-decoration
:
none
;
background
:
#cde69c
;
color
:
#638421
;
margin-right
:
5px
;
margin-bottom
:
5px
;
font-family
:
helvetica
;
font-size
:
13px
;}
div
.tagsinput
span
.tag
a
{
font-weight
:
bold
;
color
:
#82ad2b
;
text-decoration
:
none
;
font-size
:
11px
;
}
div
.tagsinput
input
{
width
:
80px
;
margin
:
0px
;
font-family
:
helvetica
;
font-size
:
13px
;
border
:
1px
solid
transparent
;
padding
:
5px
;
background
:
transparent
;
color
:
#000
;
outline
:
0px
;
margin-right
:
5px
;
margin-bottom
:
5px
;
}
div
.tagsinput
div
{
display
:
block
;
float
:
left
;
}
.tags_clear
{
clear
:
both
;
width
:
100%
;
height
:
0px
;
}
.not_valid
{
background
:
#FBD8DB
!important
;
color
:
#90111A
!important
;}
lms/static/sass/_discussion.scss
View file @
b92a180d
...
...
@@ -109,6 +109,9 @@ $discussion_input_width: 60%;
margin-top
:
10px
;
font-weight
:
bold
;
}
.tagsinput
{
margin-top
:
20px
;
}
}
.thread
{
//display: none;
...
...
@@ -127,6 +130,20 @@ $discussion_input_width: 60%;
margin-top
:
7px
;
margin-bottom
:
2px
;
}
.thread-tags
{
.thread-tag
{
@include
discussion-font
;
border-right
:
3px
solid
#205C85
;
padding-right
:
5px
;
margin-right
:
5px
;
border-radius
:
15px
;
color
:
#205C85
;
&
:hover
{
color
:
#3CC5E7
;
border-right
:
3px
solid
#3CC5E7
;
}
}
}
.info
{
@include
discussion-font
;
font-size
:
$comment_info_size
;
...
...
lms/templates/discussion/index.html
View file @
b92a180d
...
...
@@ -32,6 +32,8 @@
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/Markdown.Converter.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/Markdown.Sanitizer.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/Markdown.Editor.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/jquery.tagsinput.js')}"
></script>
<link
href=
"${static.url('css/vendor/jquery.tagsinput.css')}"
rel=
"stylesheet"
type=
"text/css"
>
</
%
block>
<
%
include
file=
"../course_navigation.html"
args=
"active_page='discussion'"
/>
...
...
lms/templates/discussion/inline.html
View file @
b92a180d
...
...
@@ -9,7 +9,7 @@
<form
class=
"new-post-form"
_id=
"${discussion_id}"
>
<input
type=
"text"
class=
"new-post-title"
placeholder=
"Title"
/>
<div
class=
"new-post-body"
></div>
<input
type=
"text"
class=
"new-pot-tags"
placeholder=
"tag1, tag2
"
/>
<input
class=
"new-post-tags"
placeholder=
"Tags
"
/>
<a
class=
"discussion-new-post"
href=
"javascript:void(0)"
>
New Post
</a>
</form>
</div>
...
...
lms/templates/discussion/thread.html
View file @
b92a180d
<
%!
from
django
.
core
.
urlresolvers
import
reverse
%
>
<
%!
from
datehelper
import
time_ago_in_words
%
>
<
%!
from
dateutil
.
parser
import
parse
%
>
<
%!
import
urllib
%
>
<
%
def
name=
"render_thread(course_id, thread, edit_thread=False, show_comments=False)"
>
<
%
...
...
@@ -9,6 +12,8 @@
else:
thread_id =
thread['id']
url_for_thread =
reverse('django_comment_client.forum.views.single_thread',
args=
[course_id,
thread_id
])
def
url_for_tags
(
tags
)
:
return
reverse
('
django_comment_client
.
forum
.
views
.
search
',
args=
[course_id])
+
'?'
+
urllib
.
urlencode
({'
tags
'
:
",".
join
(
tags
)})
%
>
<div
class=
"thread"
_id=
"${thread['id']}"
>
<div
class=
"discussion-content"
>
...
...
@@ -18,6 +23,11 @@
<a
class=
"thread-title"
name=
"${thread['id']}"
href=
"${url_for_thread}"
>
${thread['title'] | h}
</a>
<div
class=
"discussion-content-view"
>
<div
class=
"content-body thread-body"
>
${thread['body'] | h}
</div>
<div
class=
"thread-tags"
>
% for tag in thread['tags']:
<a
class=
"thread-tag"
href=
"${url_for_tags([tag])}"
>
${tag}
</a>
% endfor
</div>
<div
class=
"info"
>
${render_info(thread)}
% if edit_thread:
...
...
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