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
f6a3842f
Commit
f6a3842f
authored
Jul 28, 2012
by
Brittany Cheng
Browse files
Options
Browse Files
Download
Plain Diff
merging inline html
parents
45351880
1ad838ac
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
432 additions
and
27 deletions
+432
-27
common/lib/xmodule/xmodule/discussion_module.py
+1
-0
common/static/js/vendor/Markdown.Editor.js
+26
-9
common/static/js/vendor/customwmd.js
+0
-0
common/static/js/vendor/jquery.ajaxfileupload.js
+206
-0
lms/djangoapps/django_comment_client/base/urls.py
+1
-0
lms/djangoapps/django_comment_client/base/views.py
+93
-2
lms/djangoapps/django_comment_client/forum/views.py
+2
-1
lms/envs/common.py
+1
-0
lms/envs/discussionsettings.py
+1
-0
lms/lib/comment_client.py
+6
-0
lms/static/coffee/src/customwmd.coffee
+39
-2
lms/static/coffee/src/discussion.coffee
+13
-3
lms/templates/courseware.html
+22
-1
lms/templates/discussion/index.html
+1
-0
lms/templates/discussion/inline.html
+10
-5
lms/templates/discussion/single_thread.html
+7
-1
lms/templates/discussion/thread.html
+3
-3
No files found.
common/lib/xmodule/xmodule/discussion_module.py
View file @
f6a3842f
...
...
@@ -19,6 +19,7 @@ class DiscussionModule(XModule):
'discussion_id'
:
self
.
discussion_id
,
'search_bar'
:
''
,
'user_info'
:
comment_client
.
get_user_info
(
self
.
user_id
,
raw
=
True
),
'tags'
:
comment_client
.
get_threads_tags
(
raw
=
True
),
'course_id'
:
self
.
course_id
,
}
return
self
.
system
.
render_template
(
'discussion/inline.html'
,
context
)
...
...
common/static/js/vendor/Markdown.Editor.js
View file @
f6a3842f
...
...
@@ -28,7 +28,7 @@
// The text that appears on the upper part of the dialog box when
// entering links.
var
linkDialogText
=
"<p><b>Insert Hyperlink</b></p><p>http://example.com/
\"
optional title
\"
</p>"
;
var
imageDialogText
=
"<p><b>Insert Image
</b></p><p>http://example.com/images/diagram.jpg
\"
optional title
\"
<br><br>Need <a href='http://www.google.com/search?q=free+image+hosting' target='_blank'>free image hosting?</a
></p>"
;
var
imageDialogText
=
"<p><b>Insert Image
(upload file or type url)</b></p><p>http://example.com/images/diagram.jpg
\"
optional title
\"
<br><br
></p>"
;
// The default text that appears in the dialog input box when entering
// links.
...
...
@@ -49,7 +49,7 @@
// - getConverter() returns the markdown converter object that was passed to the constructor
// - run() actually starts the editor; should be called after all necessary plugins are registered. Calling this more than once is a no-op.
// - refreshPreview() forces the preview to be updated. This method is only available after run() was called.
Markdown
.
Editor
=
function
(
markdownConverter
,
idPostfix
,
help
)
{
Markdown
.
Editor
=
function
(
markdownConverter
,
idPostfix
,
help
,
imageUploadHandler
)
{
idPostfix
=
idPostfix
||
""
;
...
...
@@ -88,7 +88,7 @@
}
}
uiManager
=
new
UIManager
(
idPostfix
,
panels
,
undoManager
,
previewManager
,
commandManager
,
help
);
uiManager
=
new
UIManager
(
idPostfix
,
panels
,
undoManager
,
previewManager
,
commandManager
,
help
,
imageUploadHandler
);
uiManager
.
setUndoRedoButtonStates
();
var
forceRefresh
=
that
.
refreshPreview
=
function
()
{
previewManager
.
refresh
(
true
);
};
...
...
@@ -1010,7 +1010,7 @@
// callback: The function which is executed when the prompt is dismissed, either via OK or Cancel.
// It receives a single argument; either the entered text (if OK was chosen) or null (if Cancel
// was chosen).
ui
.
prompt
=
function
(
text
,
defaultInputText
,
callback
)
{
ui
.
prompt
=
function
(
text
,
defaultInputText
,
callback
,
imageUploadHandler
)
{
// These variables need to be declared at this level since they are used
// in multiple functions.
...
...
@@ -1044,8 +1044,10 @@
else
{
// Fixes common pasting errors.
text
=
text
.
replace
(
/^http:
\/\/(
https
?
|ftp
)
:
\/\/
/
,
'$1://'
);
if
(
!
/^
(?:
https
?
|ftp
)
:
\/\/
/
.
test
(
text
))
// doesn't change url if started with '/' (local)
if
(
!
/^
(?:
https
?
|ftp
)
:
\/\/
/
.
test
(
text
)
&&
text
.
charAt
(
0
)
!=
'/'
)
{
text
=
'http://'
+
text
;
}
}
dialog
.
parentNode
.
removeChild
(
dialog
);
...
...
@@ -1095,6 +1097,21 @@
style
.
marginLeft
=
style
.
marginRight
=
"auto"
;
form
.
appendChild
(
input
);
// The choose file button if prompt type is 'image'
if
(
imageUploadHandler
)
{
var
chooseFile
=
doc
.
createElement
(
"input"
);
chooseFile
.
type
=
"file"
;
chooseFile
.
name
=
"file-upload"
;
chooseFile
.
id
=
"file-upload"
;
chooseFile
.
onchange
=
function
()
{
imageUploadHandler
(
this
,
input
);
};
form
.
appendChild
(
doc
.
createElement
(
"br"
));
form
.
appendChild
(
chooseFile
);
}
// The ok button
var
okButton
=
doc
.
createElement
(
"input"
);
okButton
.
type
=
"button"
;
...
...
@@ -1160,7 +1177,7 @@
},
0
);
};
function
UIManager
(
postfix
,
panels
,
undoManager
,
previewManager
,
commandManager
,
helpOptions
)
{
function
UIManager
(
postfix
,
panels
,
undoManager
,
previewManager
,
commandManager
,
helpOptions
,
imageUploadHandler
)
{
var
inputBox
=
panels
.
input
,
buttons
=
{};
// buttons.undo, buttons.link, etc. The actual DOM elements.
...
...
@@ -1419,7 +1436,7 @@
buttons
.
quote
=
makeButton
(
"wmd-quote-button"
,
"Blockquote <blockquote> Ctrl+Q"
,
"-60px"
,
bindCommand
(
"doBlockquote"
));
buttons
.
code
=
makeButton
(
"wmd-code-button"
,
"Code Sample <pre><code> Ctrl+K"
,
"-80px"
,
bindCommand
(
"doCode"
));
buttons
.
image
=
makeButton
(
"wmd-image-button"
,
"Image <img> Ctrl+G"
,
"-100px"
,
bindCommand
(
function
(
chunk
,
postProcessing
)
{
return
this
.
doLinkOrImage
(
chunk
,
postProcessing
,
true
);
return
this
.
doLinkOrImage
(
chunk
,
postProcessing
,
true
,
imageUploadHandler
);
}));
makeSpacer
(
2
);
buttons
.
olist
=
makeButton
(
"wmd-olist-button"
,
"Numbered List <ol> Ctrl+O"
,
"-120px"
,
bindCommand
(
function
(
chunk
,
postProcessing
)
{
...
...
@@ -1649,7 +1666,7 @@
});
}
commandProto
.
doLinkOrImage
=
function
(
chunk
,
postProcessing
,
isImage
)
{
commandProto
.
doLinkOrImage
=
function
(
chunk
,
postProcessing
,
isImage
,
imageUploadHandler
)
{
chunk
.
trimWhitespace
();
chunk
.
findTags
(
/
\s
*!
?\[
/
,
/
\][
]?(?:\n[
]
*
)?(\[
.*
?\])?
/
);
...
...
@@ -1724,7 +1741,7 @@
if (isImage) {
if (!this.hooks.insertImageDialog(linkEnteredCallback))
ui.prompt(imageDialogText, imageDefaultText, linkEnteredCallback);
ui.prompt(imageDialogText, imageDefaultText, linkEnteredCallback
, imageUploadHandler
);
}
else {
ui.prompt(linkDialogText, linkDefaultText, linkEnteredCallback);
...
...
common/static/js/vendor/customwmd.js
deleted
100644 → 0
View file @
45351880
This diff is collapsed.
Click to expand it.
common/static/js/vendor/jquery.ajaxfileupload.js
0 → 100644
View file @
f6a3842f
jQuery
.
extend
({
handleError
:
function
(
s
,
xhr
,
status
,
e
)
{
// If a local callback was specified, fire it
if
(
s
.
error
)
{
s
.
error
.
call
(
s
.
context
||
s
,
xhr
,
status
,
e
);
}
// Fire the global callback
if
(
s
.
global
)
{
(
s
.
context
?
jQuery
(
s
.
context
)
:
jQuery
.
event
).
trigger
(
"ajaxError"
,
[
xhr
,
s
,
e
]
);
}
},
createUploadIframe
:
function
(
id
,
uri
){
//create frame
var
frameId
=
'jUploadFrame'
+
id
;
if
(
window
.
ActiveXObject
)
{
var
io
=
document
.
createElement
(
'<iframe id="'
+
frameId
+
'" name="'
+
frameId
+
'" />'
);
if
(
typeof
uri
==
'boolean'
){
io
.
src
=
'javascript:false'
;
}
else
if
(
typeof
uri
==
'string'
){
io
.
src
=
uri
;
}
}
else
{
var
io
=
document
.
createElement
(
'iframe'
);
io
.
id
=
frameId
;
io
.
name
=
frameId
;
}
io
.
style
.
position
=
'absolute'
;
io
.
style
.
top
=
'-1000px'
;
io
.
style
.
left
=
'-1000px'
;
document
.
body
.
appendChild
(
io
);
return
io
;
},
createUploadForm
:
function
(
id
,
fileElementId
)
{
//create form
var
formId
=
'jUploadForm'
+
id
;
var
fileId
=
'jUploadFile'
+
id
;
var
form
=
$
(
'<form action="" method="POST" name="'
+
formId
+
'" id="'
+
formId
+
'" enctype="multipart/form-data"></form>'
);
var
oldElement
=
$
(
'#'
+
fileElementId
);
var
newElement
=
$
(
oldElement
).
clone
();
$
(
oldElement
).
attr
(
'id'
,
fileId
);
$
(
oldElement
).
before
(
newElement
);
$
(
oldElement
).
appendTo
(
form
);
//set attributes
$
(
form
).
css
(
'position'
,
'absolute'
);
$
(
form
).
css
(
'top'
,
'-1200px'
);
$
(
form
).
css
(
'left'
,
'-1200px'
);
$
(
form
).
appendTo
(
'body'
);
return
form
;
},
ajaxFileUpload
:
function
(
s
)
{
// TODO introduce global settings, allowing the client to modify them for all requests, not only timeout
s
=
jQuery
.
extend
({},
jQuery
.
ajaxSettings
,
s
);
var
id
=
new
Date
().
getTime
()
var
form
=
jQuery
.
createUploadForm
(
id
,
s
.
fileElementId
);
var
io
=
jQuery
.
createUploadIframe
(
id
,
s
.
secureuri
);
var
frameId
=
'jUploadFrame'
+
id
;
var
formId
=
'jUploadForm'
+
id
;
// Watch for a new set of requests
if
(
s
.
global
&&
!
jQuery
.
active
++
)
{
jQuery
.
event
.
trigger
(
"ajaxStart"
);
}
var
requestDone
=
false
;
// Create the request object
var
xml
=
{}
if
(
s
.
global
)
jQuery
.
event
.
trigger
(
"ajaxSend"
,
[
xml
,
s
]);
// Wait for a response to come back
var
uploadCallback
=
function
(
isTimeout
)
{
var
io
=
document
.
getElementById
(
frameId
);
try
{
if
(
io
.
contentWindow
){
xml
.
responseText
=
io
.
contentWindow
.
document
.
body
?
io
.
contentWindow
.
document
.
body
.
innerText
:
null
;
xml
.
responseXML
=
io
.
contentWindow
.
document
.
XMLDocument
?
io
.
contentWindow
.
document
.
XMLDocument
:
io
.
contentWindow
.
document
;
}
else
if
(
io
.
contentDocument
)
{
xml
.
responseText
=
io
.
contentDocument
.
document
.
body
?
io
.
contentDocument
.
document
.
body
.
textContent
||
document
.
body
.
innerText
:
null
;
xml
.
responseXML
=
io
.
contentDocument
.
document
.
XMLDocument
?
io
.
contentDocument
.
document
.
XMLDocument
:
io
.
contentDocument
.
document
;
}
}
catch
(
e
)
{
jQuery
.
handleError
(
s
,
xml
,
null
,
e
);
}
if
(
xml
||
isTimeout
==
"timeout"
)
{
requestDone
=
true
;
var
status
;
try
{
status
=
isTimeout
!=
"timeout"
?
"success"
:
"error"
;
// Make sure that the request was successful or notmodified
if
(
status
!=
"error"
)
{
// process the data (runs the xml through httpData regardless of callback)
var
data
=
jQuery
.
uploadHttpData
(
xml
,
s
.
dataType
);
// If a local callback was specified, fire it and pass it the data
if
(
s
.
success
)
s
.
success
(
data
,
status
);
// Fire the global callback
if
(
s
.
global
)
jQuery
.
event
.
trigger
(
"ajaxSuccess"
,
[
xml
,
s
]
);
}
else
jQuery
.
handleError
(
s
,
xml
,
status
);
}
catch
(
e
)
{
status
=
"error"
;
jQuery
.
handleError
(
s
,
xml
,
status
,
e
);
}
// The request was completed
if
(
s
.
global
)
jQuery
.
event
.
trigger
(
"ajaxComplete"
,
[
xml
,
s
]
);
// Handle the global AJAX counter
if
(
s
.
global
&&
!
--
jQuery
.
active
)
jQuery
.
event
.
trigger
(
"ajaxStop"
);
// Process result
if
(
s
.
complete
)
s
.
complete
(
xml
,
status
);
jQuery
(
io
).
unbind
();
setTimeout
(
function
()
{
try
{
$
(
io
).
remove
();
$
(
form
).
remove
();
}
catch
(
e
)
{
jQuery
.
handleError
(
s
,
xml
,
null
,
e
);
}
},
100
)
xml
=
null
;
}
}
// Timeout checker
if
(
s
.
timeout
>
0
)
{
setTimeout
(
function
(){
// Check to see if the request is still happening
if
(
!
requestDone
)
uploadCallback
(
"timeout"
);
},
s
.
timeout
);
}
try
{
// var io = $('#' + frameId);
var
form
=
$
(
'#'
+
formId
);
$
(
form
).
attr
(
'action'
,
s
.
url
);
$
(
form
).
attr
(
'method'
,
'POST'
);
$
(
form
).
attr
(
'target'
,
frameId
);
if
(
form
.
encoding
)
{
form
.
encoding
=
'multipart/form-data'
;
}
else
{
form
.
enctype
=
'multipart/form-data'
;
}
$
(
form
).
submit
();
}
catch
(
e
)
{
jQuery
.
handleError
(
s
,
xml
,
null
,
e
);
}
if
(
window
.
attachEvent
){
document
.
getElementById
(
frameId
).
attachEvent
(
'onload'
,
uploadCallback
);
}
else
{
document
.
getElementById
(
frameId
).
addEventListener
(
'load'
,
uploadCallback
,
false
);
}
return
{
abort
:
function
()
{}};
},
uploadHttpData
:
function
(
r
,
type
)
{
var
data
=
!
type
;
data
=
type
==
"xml"
||
data
?
r
.
responseXML
:
r
.
responseText
;
// If the type is "script", eval it in global context
if
(
type
==
"script"
)
jQuery
.
globalEval
(
data
);
// Get the JavaScript object, if JSON is used.
if
(
type
==
"json"
)
eval
(
"data = "
+
data
);
// evaluate scripts within html
if
(
type
==
"html"
)
jQuery
(
"<div>"
).
html
(
data
).
evalScripts
();
//alert($('param', data).each(function(){alert($(this).attr('value'));}));
return
data
;
}
})
lms/djangoapps/django_comment_client/base/urls.py
View file @
f6a3842f
...
...
@@ -3,6 +3,7 @@ import django_comment_client.base.views
urlpatterns
=
patterns
(
'django_comment_client.base.views'
,
url
(
r'upload$'
,
'upload'
,
name
=
'upload'
),
url
(
r'threads/(?P<thread_id>[\w\-]+)/update$'
,
'update_thread'
,
name
=
'update_thread'
),
url
(
r'threads/(?P<thread_id>[\w\-]+)/reply$'
,
'create_comment'
,
name
=
'create_comment'
),
url
(
r'threads/(?P<thread_id>[\w\-]+)/delete'
,
'delete_thread'
,
name
=
'delete_thread'
),
...
...
lms/djangoapps/django_comment_client/base/views.py
View file @
f6a3842f
import
time
import
random
import
os
import
os.path
import
logging
import
urlparse
import
comment_client
from
django.core
import
exceptions
from
django.contrib.auth.decorators
import
login_required
from
django.views.decorators.http
import
require_POST
,
require_GET
from
django.http
import
HttpResponse
from
django.utils
import
simplejson
import
comment_client
from
django.views.decorators
import
csrf
from
django.core.files.storage
import
get_storage_class
from
django.utils.translation
import
ugettext
as
_
from
django.conf
import
settings
class
JsonResponse
(
HttpResponse
):
def
__init__
(
self
,
data
=
None
):
...
...
@@ -183,3 +195,82 @@ def search(request, course_id):
commentable_id
=
request
.
GET
.
get
(
'commentable_id'
,
None
)
response
=
comment_client
.
search
(
text
,
commentable_id
)
return
JsonResponse
(
response
)
@csrf.csrf_exempt
@login_required
@require_POST
def
upload
(
request
,
course_id
):
#ajax upload file to a question or answer
"""view that handles file upload via Ajax
"""
# check upload permission
result
=
''
error
=
''
new_file_name
=
''
try
:
# TODO authorization
#may raise exceptions.PermissionDenied
#if request.user.is_anonymous():
# msg = _('Sorry, anonymous users cannot upload files')
# raise exceptions.PermissionDenied(msg)
#request.user.assert_can_upload_file()
# check file type
f
=
request
.
FILES
[
'file-upload'
]
file_extension
=
os
.
path
.
splitext
(
f
.
name
)[
1
]
.
lower
()
if
not
file_extension
in
settings
.
DISCUSSION_ALLOWED_UPLOAD_FILE_TYPES
:
file_types
=
"', '"
.
join
(
settings
.
DISCUSSION_ALLOWED_UPLOAD_FILE_TYPES
)
msg
=
_
(
"allowed file types are '
%(file_types)
s'"
)
%
\
{
'file_types'
:
file_types
}
raise
exceptions
.
PermissionDenied
(
msg
)
# generate new file name
new_file_name
=
str
(
time
.
time
()
)
.
replace
(
'.'
,
str
(
random
.
randint
(
0
,
100000
))
)
+
file_extension
file_storage
=
get_storage_class
()()
# use default storage to store file
file_storage
.
save
(
new_file_name
,
f
)
# check file size
# byte
size
=
file_storage
.
size
(
new_file_name
)
if
size
>
settings
.
ASKBOT_MAX_UPLOAD_FILE_SIZE
:
file_storage
.
delete
(
new_file_name
)
msg
=
_
(
"maximum upload file size is
%(file_size)
sK"
)
%
\
{
'file_size'
:
settings
.
ASKBOT_MAX_UPLOAD_FILE_SIZE
}
raise
exceptions
.
PermissionDenied
(
msg
)
except
exceptions
.
PermissionDenied
,
e
:
error
=
unicode
(
e
)
except
Exception
,
e
:
logging
.
critical
(
unicode
(
e
))
error
=
_
(
'Error uploading file. Please contact the site administrator. Thank you.'
)
if
error
==
''
:
result
=
'Good'
file_url
=
file_storage
.
url
(
new_file_name
)
parsed_url
=
urlparse
.
urlparse
(
file_url
)
file_url
=
urlparse
.
urlunparse
(
urlparse
.
ParseResult
(
parsed_url
.
scheme
,
parsed_url
.
netloc
,
parsed_url
.
path
,
''
,
''
,
''
)
)
else
:
result
=
''
file_url
=
''
return
JsonResponse
({
'result'
:
{
'msg'
:
result
,
'error'
:
error
,
'file_url'
:
file_url
,
}
})
lms/djangoapps/django_comment_client/forum/views.py
View file @
f6a3842f
...
...
@@ -32,6 +32,7 @@ def render_discussion(request, course_id, threads, discussion_id=None, search_te
'discussion_id'
:
discussion_id
,
'search_bar'
:
render_search_bar
(
request
,
course_id
,
discussion_id
,
text
=
search_text
),
'user_info'
:
comment_client
.
get_user_info
(
request
.
user
.
id
,
raw
=
True
),
'tags'
:
comment_client
.
get_threads_tags
(
raw
=
True
),
'course_id'
:
course_id
,
}
return
render_to_string
(
'discussion/inline.html'
,
context
)
...
...
@@ -78,6 +79,7 @@ def render_single_thread(request, course_id, thread_id):
context
=
{
'thread'
:
comment_client
.
get_thread
(
thread_id
,
recursive
=
True
),
'user_info'
:
comment_client
.
get_user_info
(
request
.
user
.
id
,
raw
=
True
),
'tags'
:
comment_client
.
get_threads_tags
(
raw
=
True
),
'course_id'
:
course_id
,
}
return
render_to_string
(
'discussion/single_thread.html'
,
context
)
...
...
@@ -91,7 +93,6 @@ def single_thread(request, course_id, thread_id):
'init'
:
''
,
'content'
:
render_single_thread
(
request
,
course_id
,
thread_id
),
'accordion'
:
''
,
'user_info'
:
comment_client
.
get_user_info
(
request
.
user
.
id
,
raw
=
True
),
'course'
:
course
,
}
...
...
lms/envs/common.py
View file @
f6a3842f
...
...
@@ -30,6 +30,7 @@ import djcelery
from
path
import
path
from
.askbotsettings
import
*
# this is where LIVESETTINGS_OPTIONS comes from
from
.discussionsettings
import
*
################################### FEATURES ###################################
COURSEWARE_ENABLED
=
True
...
...
lms/envs/discussionsettings.py
0 → 100644
View file @
f6a3842f
DISCUSSION_ALLOWED_UPLOAD_FILE_TYPES
=
(
'.jpg'
,
'.jpeg'
,
'.gif'
,
'.bmp'
,
'.png'
,
'.tiff'
)
lms/lib/comment_client.py
View file @
f6a3842f
...
...
@@ -11,6 +11,9 @@ def delete_threads(commentable_id, *args, **kwargs):
def
get_threads
(
commentable_id
,
recursive
=
False
,
*
args
,
**
kwargs
):
return
_perform_request
(
'get'
,
_url_for_threads
(
commentable_id
),
{
'recursive'
:
recursive
},
*
args
,
**
kwargs
)
def
get_threads_tags
(
*
args
,
**
kwargs
):
return
_perform_request
(
'get'
,
_url_for_threads_tags
(),
{},
*
args
,
**
kwargs
)
def
create_thread
(
commentable_id
,
attributes
,
*
args
,
**
kwargs
):
return
_perform_request
(
'post'
,
_url_for_threads
(
commentable_id
),
attributes
,
*
args
,
**
kwargs
)
...
...
@@ -126,3 +129,6 @@ def _url_for_user(user_id):
def
_url_for_search
():
return
"{prefix}/search"
.
format
(
prefix
=
PREFIX
)
def
_url_for_threads_tags
():
return
"{prefix}/threads/tags"
.
format
(
prefix
=
PREFIX
)
lms/static/coffee/src/customwmd.coffee
View file @
f6a3842f
...
...
@@ -102,6 +102,7 @@ $ ->
text
if
Markdown
?
Markdown
.
getMathCompatibleConverter
=
->
converter
=
Markdown
.
getSanitizingConverter
()
processor
=
new
MathJaxProcessor
()
...
...
@@ -109,11 +110,13 @@ $ ->
converter
.
hooks
.
chain
"postConversion"
,
processor
.
replaceMath
converter
Markdown
.
makeWmdEditor
=
(
elem
,
appended_id
)
->
Markdown
.
makeWmdEditor
=
(
elem
,
appended_id
,
imageUploadUrl
)
->
$elem
=
$
(
elem
)
if
not
$elem
.
length
console
.
log
"warning: elem for makeWmdEditor doesn't exist"
return
if
not
$elem
.
find
(
".wmd-panel"
).
length
_append
=
appended_id
||
""
$wmdPanel
=
$
(
"<div>"
).
addClass
(
"wmd-panel"
)
...
...
@@ -121,8 +124,42 @@ $ ->
.
append
(
$
(
"<textarea>"
).
addClass
(
"wmd-input"
).
attr
(
"id"
,
"wmd-input
#{
_append
}
"
))
.
append
(
$
(
"<div>"
).
attr
(
"id"
,
"wmd-preview
#{
_append
}
"
).
addClass
(
"wmd-panel wmd-preview"
))
$elem
.
append
(
$wmdPanel
)
converter
=
Markdown
.
getMathCompatibleConverter
()
editor
=
new
Markdown
.
Editor
(
converter
,
appended_id
)
ajaxFileUpload
=
(
imageUploadUrl
,
input
,
startUploadHandler
)
->
$
(
"#loading"
).
ajaxStart
(
->
$
(
this
).
show
()).
ajaxComplete
(
->
$
(
this
).
hide
())
$
(
"#upload"
).
ajaxStart
(
->
$
(
this
).
hide
()).
ajaxComplete
(
->
$
(
this
).
show
())
$
.
ajaxFileUpload
url
:
imageUploadUrl
secureuri
:
false
fileElementId
:
'file-upload'
dataType
:
'json'
success
:
(
data
,
status
)
->
fileURL
=
data
[
'result'
][
'file_url'
]
error
=
data
[
'result'
][
'error'
]
if
error
!=
''
alert
error
if
startUploadHandler
$
(
'#file-upload'
).
unbind
(
'change'
).
change
(
startUploadHandler
)
console
.
log
error
else
$
(
input
).
attr
(
'value'
,
fileURL
)
error
:
(
data
,
status
,
e
)
->
alert
(
e
)
if
startUploadHandler
$
(
'#file-upload'
).
unbind
(
'change'
).
change
(
startUploadHandler
)
imageUploadHandler
=
(
elem
,
input
)
->
console
.
log
"here"
ajaxFileUpload
(
imageUploadUrl
,
input
,
imageUploadHandler
)
editor
=
new
Markdown
.
Editor
(
converter
,
appended_id
,
# idPostfix
null
,
# help handler
imageUploadHandler
)
delayRenderer
=
new
MathJaxDelayRenderer
()
editor
.
hooks
.
chain
"onPreviewPush"
,
(
text
,
previewSet
)
->
delayRenderer
.
render
...
...
lms/static/coffee/src/discussion.coffee
View file @
f6a3842f
...
...
@@ -43,6 +43,7 @@ Discussion =
delete_comment
:
"/courses/
#{
$$course_id
}
/discussion/comments/
#{
param
}
/delete"
upvote_comment
:
"/courses/
#{
$$course_id
}
/discussion/comments/
#{
param
}
/upvote"
downvote_comment
:
"/courses/
#{
$$course_id
}
/discussion/comments/
#{
param
}
/downvote"
upload
:
"/courses/
#{
$$course_id
}
/discussion/upload"
search
:
"/courses/
#{
$$course_id
}
/discussion/forum/search"
}[
name
]
...
...
@@ -89,7 +90,7 @@ Discussion =
newPostBody
=
$
(
discussion
).
find
(
".new-post-body"
)
if
newPostBody
.
length
Markdown
.
makeWmdEditor
newPostBody
,
"-new-post-body-
#{
$
(
discussion
).
attr
(
'_id'
)
}
"
Markdown
.
makeWmdEditor
newPostBody
,
"-new-post-body-
#{
$
(
discussion
).
attr
(
'_id'
)
}
"
,
Discussion
.
urlFor
(
'upload'
)
initializeWatchThreads
=
(
index
,
thread
)
->
$thread
=
$
(
thread
)
...
...
@@ -175,7 +176,7 @@ Discussion =
$discussionContent
.
append
(
editView
)
Markdown
.
makeWmdEditor
$local
(
".comment-edit"
),
"-comment-edit-
#{
id
}
"
Markdown
.
makeWmdEditor
$local
(
".comment-edit"
),
"-comment-edit-
#{
id
}
"
,
Discussion
.
urlFor
(
'upload'
)
cancelReply
=
generateDiscussionLink
(
"discussion-cancel-reply"
,
"Cancel"
,
handleCancelReply
)
submitReply
=
generateDiscussionLink
(
"discussion-submit-reply"
,
"Submit"
,
handleSubmitReply
)
$local
(
".discussion-link"
).
hide
()
...
...
@@ -230,10 +231,17 @@ Discussion =
$local
(
".discussion-vote-down"
).
click
->
handleVote
(
this
,
"down"
)
initializeContent
:
(
content
)
->
$content
=
$
(
content
)
$local
=
generateLocal
(
$content
.
children
(
".discussion-content"
))
raw_text
=
$local
(
".content-body"
).
html
()
converter
=
Markdown
.
getMathCompatibleConverter
()
$local
(
".content-body"
).
html
(
converter
.
makeHtml
(
raw_text
))
bindDiscussionEvents
:
(
discussion
)
->
$discussion
=
$
(
discussion
)
$discussionNonContent
=
$discussion
.
children
(
".discussion-non-content"
)
$local
=
(
selector
)
->
$discussionNonContent
.
find
(
selector
)
$local
=
generateLocal
(
$discussionNonContent
)
#
(selector) -> $discussionNonContent.find(selector)
id
=
$discussion
.
attr
(
"_id"
)
...
...
@@ -266,7 +274,9 @@ Discussion =
$local
(
".new-post-form"
).
submit
()
$discussion
.
find
(
".thread"
).
each
(
index
,
thread
)
->
Discussion
.
initializeContent
(
thread
)
Discussion
.
bindContentEvents
(
thread
)
$discussion
.
find
(
".comment"
).
each
(
index
,
comment
)
->
Discussion
.
initializeContent
(
comment
)
Discussion
.
bindContentEvents
(
comment
)
lms/templates/courseware.html
View file @
f6a3842f
...
...
@@ -28,7 +28,28 @@
<
%
static:js
group=
'courseware'
/>
<
%
include
file=
"mathjax_include.html"
/>
<script
type=
"text/x-mathjax-config"
>
MathJax
.
Hub
.
Config
({
tex2jax
:
{
inlineMath
:
[
[
"$"
,
"$"
],
],
displayMath
:
[
[
"$$"
,
"$$"
],
]
}
});
</script>
<!-- This must appear after all mathjax-config blocks, so it is after the imports from the other templates.
It can't be run through static.url because MathJax uses crazy url introspection to do lazy loading of
MathJax extension libraries -->
<script
type=
"text/javascript"
src=
"/static/js/vendor/mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-MML-AM_HTMLorMML-full"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/split.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/jquery.ajaxfileupload.js')}"
></script>
<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>
<!-- TODO: http://docs.jquery.com/Plugins/Validation -->
<script
type=
"text/javascript"
>
...
...
lms/templates/discussion/index.html
View file @
f6a3842f
...
...
@@ -27,6 +27,7 @@
## It can't be run through static.url because MathJax uses crazy url introspection to do lazy loading of MathJax extension libraries
<script
type=
"text/javascript"
src=
"/static/js/vendor/mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-MML-AM_HTMLorMML-full"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/split.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/jquery.ajaxfileupload.js')}"
></script>
<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>
...
...
lms/templates/discussion/inline.html
View file @
f6a3842f
...
...
@@ -7,11 +7,10 @@
</div>
${search_bar}
<form
class=
"new-post-form"
_id=
"${discussion_id}"
>
<input
class=
"searchInput"
type=
"text"
autocomplete=
"off"
placeholder=
"Comment Text
"
/>
<div
class=
"new-post-body"
>
<
/div
>
<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"
/
>
<a
class=
"discussion-new-post"
href=
"javascript:void(0)"
>
New Post
</a>
</form>
</div>
% for thread in threads:
...
...
@@ -19,7 +18,13 @@
% endfor
</section>
<
%!
def
escape_quotes
(
text
)
:
return
text
.
replace
('\"',
'\\\"').
replace
("\'",
"\\\'")
%
>
<script
type=
"text/javascript"
>
var
$$user_info
=
JSON
.
parse
(
'${user_info}'
);
var
$$user_info
=
JSON
.
parse
(
'${user_info
| escape_quotes
}'
);
var
$$course_id
=
"${course_id}"
;
var
$$tags
=
JSON
.
parse
(
"${tags | escape_quotes}"
);
</script>
lms/templates/discussion/single_thread.html
View file @
f6a3842f
...
...
@@ -5,7 +5,13 @@
${renderer.render_thread(course_id, thread, edit_thread=True, show_comments=True)}
</section>
<
%!
def
escape_quotes
(
text
)
:
return
text
.
replace
('\"',
'\\\"').
replace
("\'",
"\\\'")
%
>
<script
type=
"text/javascript"
>
var
$$user_info
=
JSON
.
parse
(
'${user_info}'
);
var
$$user_info
=
JSON
.
parse
(
'${user_info
| escape_quotes
}'
);
var
$$course_id
=
"${course_id}"
;
var
$$tags
=
JSON
.
parse
(
"${tags | escape_quotes}"
);
</script>
lms/templates/discussion/thread.html
View file @
f6a3842f
...
...
@@ -15,9 +15,9 @@
<div
class=
"discussion-upper-wrapper clearfix"
>
${render_vote(thread)}
<div
class=
"discussion-right-wrapper clearfix"
>
<a
class=
"thread-title"
name=
"${thread['id']}"
href=
"${url_for_thread}"
>
${thread['title']}
</a>
<a
class=
"thread-title"
name=
"${thread['id']}"
href=
"${url_for_thread}"
>
${thread['title']
| h
}
</a>
<div
class=
"discussion-content-view"
>
<div
class=
"
thread-body"
>
${thread['body']
}
</div>
<div
class=
"
content-body thread-body"
>
${thread['body'] | h
}
</div>
<div
class=
"info"
>
${render_info(thread)}
% if edit_thread:
...
...
@@ -45,7 +45,7 @@
${render_vote(comment)}
<div
class=
"discussion-right-wrapper"
>
<div
class=
"discussion-content-view"
>
<a
class=
"co
mment-body"
name=
"${comment['id']}"
>
${comment['body']
}
</a>
<a
class=
"co
ntent-body comment-body"
name=
"${comment['id']}"
>
${comment['body'] | h
}
</a>
<div
class=
"info"
>
${render_info(comment)}
${render_reply()}
...
...
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