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
d2b26991
Commit
d2b26991
authored
Jun 06, 2014
by
Julia Hansbrough
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3969 from lduarte1991/lduarte-harvardx-pr2
Annotation Tool: Urgent update for ChinaX AB Testing
parents
3584d571
dc9ae84e
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
357 additions
and
236 deletions
+357
-236
common/lib/xmodule/xmodule/annotator_mixin.py
+37
-0
common/lib/xmodule/xmodule/imageannotation_module.py
+6
-16
common/lib/xmodule/xmodule/textannotation_module.py
+6
-15
common/lib/xmodule/xmodule/videoannotation_module.py
+7
-15
common/static/js/vendor/ova/OpenSeaDragonAnnotation.js
+14
-13
common/static/js/vendor/ova/catch/css/main.css
+15
-5
common/static/js/vendor/ova/catch/js/catch.js
+119
-52
lms/djangoapps/notes/views.py
+5
-3
lms/templates/imageannotation.html
+95
-79
lms/templates/notes.html
+28
-26
lms/templates/textannotation.html
+13
-6
lms/templates/videoannotation.html
+12
-6
No files found.
common/lib/xmodule/xmodule/annotator_mixin.py
View file @
d2b26991
...
@@ -6,7 +6,10 @@ from lxml import etree
...
@@ -6,7 +6,10 @@ from lxml import etree
from
urlparse
import
urlparse
from
urlparse
import
urlparse
from
os.path
import
splitext
,
basename
from
os.path
import
splitext
,
basename
from
HTMLParser
import
HTMLParser
from
HTMLParser
import
HTMLParser
from
xblock.core
import
Scope
,
String
# Make '_' a no-op so we can scrape strings
_
=
lambda
text
:
text
def
get_instructions
(
xmltree
):
def
get_instructions
(
xmltree
):
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
""" Removes <instructions> from the xmltree and returns them as a string, otherwise None. """
...
@@ -53,3 +56,37 @@ def html_to_text(html):
...
@@ -53,3 +56,37 @@ def html_to_text(html):
htmlstripper
=
MLStripper
()
htmlstripper
=
MLStripper
()
htmlstripper
.
feed
(
html
)
htmlstripper
.
feed
(
html
)
return
htmlstripper
.
get_data
()
return
htmlstripper
.
get_data
()
class
CommonAnnotatorMixin
(
object
):
annotation_storage_url
=
String
(
help
=
_
(
"Location of Annotation backend"
),
scope
=
Scope
.
settings
,
default
=
"http://your_annotation_storage.com"
,
display_name
=
_
(
"Url for Annotation Storage"
)
)
annotation_token_secret
=
String
(
help
=
_
(
"Secret string for annotation storage"
),
scope
=
Scope
.
settings
,
default
=
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
,
display_name
=
_
(
"Secret Token String for Annotation"
)
)
default_tab
=
String
(
display_name
=
_
(
"Default Annotations Tab"
),
help
=
_
(
"Select which tab will be the default in the annotations table: myNotes, Instructor, or Public."
),
scope
=
Scope
.
settings
,
default
=
"myNotes"
,
)
# currently only supports one instructor, will build functionality for multiple later
instructor_email
=
String
(
display_name
=
_
(
"Email for 'Instructor' Annotations"
),
help
=
_
(
"Email of the user that will be attached to all annotations that will be found in 'Instructor' tab."
),
scope
=
Scope
.
settings
,
default
=
""
,
)
annotation_mode
=
String
(
display_name
=
_
(
"Mode for Annotation Tool"
),
help
=
_
(
"Type in number corresponding to following modes: 'instructor' or 'everyone'"
),
scope
=
Scope
.
settings
,
default
=
"everyone"
,
)
common/lib/xmodule/xmodule/imageannotation_module.py
View file @
d2b26991
...
@@ -7,7 +7,7 @@ from pkg_resources import resource_string
...
@@ -7,7 +7,7 @@ from pkg_resources import resource_string
from
xmodule.x_module
import
XModule
from
xmodule.x_module
import
XModule
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.raw_module
import
RawDescriptor
from
xblock.core
import
Scope
,
String
from
xblock.core
import
Scope
,
String
from
xmodule.annotator_mixin
import
get_instructions
,
html_to_text
from
xmodule.annotator_mixin
import
CommonAnnotatorMixin
,
get_instructions
,
html_to_text
from
xmodule.annotator_token
import
retrieve_token
from
xmodule.annotator_token
import
retrieve_token
from
xblock.fragment
import
Fragment
from
xblock.fragment
import
Fragment
...
@@ -51,21 +51,9 @@ class AnnotatableFields(object):
...
@@ -51,21 +51,9 @@ class AnnotatableFields(object):
scope
=
Scope
.
settings
,
scope
=
Scope
.
settings
,
default
=
'professor:green,teachingAssistant:blue'
,
default
=
'professor:green,teachingAssistant:blue'
,
)
)
annotation_storage_url
=
String
(
help
=
_
(
"Location of Annotation backend"
),
scope
=
Scope
.
settings
,
default
=
"http://your_annotation_storage.com"
,
display_name
=
_
(
"Url for Annotation Storage"
)
)
annotation_token_secret
=
String
(
help
=
_
(
"Secret string for annotation storage"
),
scope
=
Scope
.
settings
,
default
=
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
,
display_name
=
_
(
"Secret Token String for Annotation"
)
)
class
ImageAnnotationModule
(
AnnotatableFields
,
XModule
):
class
ImageAnnotationModule
(
AnnotatableFields
,
CommonAnnotatorMixin
,
XModule
):
'''Image Annotation Module'''
'''Image Annotation Module'''
js
=
{
js
=
{
'coffee'
:
[
'coffee'
:
[
...
@@ -100,12 +88,14 @@ class ImageAnnotationModule(AnnotatableFields, XModule):
...
@@ -100,12 +88,14 @@ class ImageAnnotationModule(AnnotatableFields, XModule):
context
=
{
context
=
{
'display_name'
:
self
.
display_name_with_default
,
'display_name'
:
self
.
display_name_with_default
,
'instructions_html'
:
self
.
instructions
,
'instructions_html'
:
self
.
instructions
,
'annotation_storage'
:
self
.
annotation_storage_url
,
'token'
:
retrieve_token
(
self
.
user
,
self
.
annotation_token_secret
),
'token'
:
retrieve_token
(
self
.
user
,
self
.
annotation_token_secret
),
'tag'
:
self
.
instructor_tags
,
'tag'
:
self
.
instructor_tags
,
'openseadragonjson'
:
self
.
openseadragonjson
,
'openseadragonjson'
:
self
.
openseadragonjson
,
'annotation_storage'
:
self
.
annotation_storage_url
,
'default_tab'
:
self
.
default_tab
,
'instructor_email'
:
self
.
instructor_email
,
'annotation_mode'
:
self
.
annotation_mode
,
}
}
fragment
=
Fragment
(
self
.
system
.
render_template
(
'imageannotation.html'
,
context
))
fragment
=
Fragment
(
self
.
system
.
render_template
(
'imageannotation.html'
,
context
))
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js"
)
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js"
)
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js"
)
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js"
)
...
...
common/lib/xmodule/xmodule/textannotation_module.py
View file @
d2b26991
...
@@ -6,7 +6,7 @@ from pkg_resources import resource_string
...
@@ -6,7 +6,7 @@ from pkg_resources import resource_string
from
xmodule.x_module
import
XModule
from
xmodule.x_module
import
XModule
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.raw_module
import
RawDescriptor
from
xblock.core
import
Scope
,
String
from
xblock.core
import
Scope
,
String
from
xmodule.annotator_mixin
import
get_instructions
from
xmodule.annotator_mixin
import
CommonAnnotatorMixin
,
get_instructions
from
xmodule.annotator_token
import
retrieve_token
from
xmodule.annotator_token
import
retrieve_token
from
xblock.fragment
import
Fragment
from
xblock.fragment
import
Fragment
import
textwrap
import
textwrap
...
@@ -47,18 +47,6 @@ class AnnotatableFields(object):
...
@@ -47,18 +47,6 @@ class AnnotatableFields(object):
scope
=
Scope
.
settings
,
scope
=
Scope
.
settings
,
default
=
'None'
,
default
=
'None'
,
)
)
annotation_storage_url
=
String
(
help
=
_
(
"Location of Annotation backend"
),
scope
=
Scope
.
settings
,
default
=
"http://your_annotation_storage.com"
,
display_name
=
_
(
"Url for Annotation Storage"
),
)
annotation_token_secret
=
String
(
help
=
_
(
"Secret string for annotation storage"
),
scope
=
Scope
.
settings
,
default
=
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
,
display_name
=
_
(
"Secret Token String for Annotation"
),
)
diacritics
=
String
(
diacritics
=
String
(
display_name
=
_
(
"Diacritic Marks"
),
display_name
=
_
(
"Diacritic Marks"
),
help
=
_
(
"Add diacritic marks to be added to a text using the comma-separated form, i.e. markname;urltomark;baseline,markname2;urltomark2;baseline2"
),
help
=
_
(
"Add diacritic marks to be added to a text using the comma-separated form, i.e. markname;urltomark;baseline,markname2;urltomark2;baseline2"
),
...
@@ -67,7 +55,7 @@ class AnnotatableFields(object):
...
@@ -67,7 +55,7 @@ class AnnotatableFields(object):
)
)
class
TextAnnotationModule
(
AnnotatableFields
,
XModule
):
class
TextAnnotationModule
(
AnnotatableFields
,
CommonAnnotatorMixin
,
XModule
):
''' Text Annotation Module '''
''' Text Annotation Module '''
js
=
{
'coffee'
:
[],
js
=
{
'coffee'
:
[],
'js'
:
[]}
'js'
:
[]}
...
@@ -98,9 +86,12 @@ class TextAnnotationModule(AnnotatableFields, XModule):
...
@@ -98,9 +86,12 @@ class TextAnnotationModule(AnnotatableFields, XModule):
'source'
:
self
.
source
,
'source'
:
self
.
source
,
'instructions_html'
:
self
.
instructions
,
'instructions_html'
:
self
.
instructions
,
'content_html'
:
self
.
content
,
'content_html'
:
self
.
content
,
'annotation_storage'
:
self
.
annotation_storage_url
,
'token'
:
retrieve_token
(
self
.
user_email
,
self
.
annotation_token_secret
),
'token'
:
retrieve_token
(
self
.
user_email
,
self
.
annotation_token_secret
),
'diacritic_marks'
:
self
.
diacritics
,
'diacritic_marks'
:
self
.
diacritics
,
'annotation_storage'
:
self
.
annotation_storage_url
,
'default_tab'
:
self
.
default_tab
,
'instructor_email'
:
self
.
instructor_email
,
'annotation_mode'
:
self
.
annotation_mode
,
}
}
fragment
=
Fragment
(
self
.
system
.
render_template
(
'textannotation.html'
,
context
))
fragment
=
Fragment
(
self
.
system
.
render_template
(
'textannotation.html'
,
context
))
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js"
)
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js"
)
...
...
common/lib/xmodule/xmodule/videoannotation_module.py
View file @
d2b26991
...
@@ -7,7 +7,7 @@ from pkg_resources import resource_string
...
@@ -7,7 +7,7 @@ from pkg_resources import resource_string
from
xmodule.x_module
import
XModule
from
xmodule.x_module
import
XModule
from
xmodule.raw_module
import
RawDescriptor
from
xmodule.raw_module
import
RawDescriptor
from
xblock.core
import
Scope
,
String
from
xblock.core
import
Scope
,
String
from
xmodule.annotator_mixin
import
get_instructions
,
get_extension
from
xmodule.annotator_mixin
import
CommonAnnotatorMixin
,
get_instructions
,
get_extension
from
xmodule.annotator_token
import
retrieve_token
from
xmodule.annotator_token
import
retrieve_token
from
xblock.fragment
import
Fragment
from
xblock.fragment
import
Fragment
...
@@ -45,20 +45,9 @@ class AnnotatableFields(object):
...
@@ -45,20 +45,9 @@ class AnnotatableFields(object):
scope
=
Scope
.
settings
,
scope
=
Scope
.
settings
,
default
=
""
default
=
""
)
)
annotation_storage_url
=
String
(
help
=
_
(
"Location of Annotation backend"
),
scope
=
Scope
.
settings
,
default
=
"http://your_annotation_storage.com"
,
display_name
=
_
(
"Url for Annotation Storage"
),
)
annotation_token_secret
=
String
(
help
=
_
(
"Secret string for annotation storage"
),
scope
=
Scope
.
settings
,
default
=
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
,
display_name
=
_
(
"Secret Token String for Annotation"
)
)
class
VideoAnnotationModule
(
AnnotatableFields
,
XModule
):
class
VideoAnnotationModule
(
AnnotatableFields
,
CommonAnnotatorMixin
,
XModule
):
'''Video Annotation Module'''
'''Video Annotation Module'''
js
=
{
js
=
{
'coffee'
:
[
'coffee'
:
[
...
@@ -104,8 +93,11 @@ class VideoAnnotationModule(AnnotatableFields, XModule):
...
@@ -104,8 +93,11 @@ class VideoAnnotationModule(AnnotatableFields, XModule):
'typeSource'
:
extension
,
'typeSource'
:
extension
,
'poster'
:
self
.
poster_url
,
'poster'
:
self
.
poster_url
,
'content_html'
:
self
.
content
,
'content_html'
:
self
.
content
,
'annotation_storage'
:
self
.
annotation_storage_url
,
'token'
:
retrieve_token
(
self
.
user_email
,
self
.
annotation_token_secret
),
'token'
:
retrieve_token
(
self
.
user_email
,
self
.
annotation_token_secret
),
'annotation_storage'
:
self
.
annotation_storage_url
,
'default_tab'
:
self
.
default_tab
,
'instructor_email'
:
self
.
instructor_email
,
'annotation_mode'
:
self
.
annotation_mode
,
}
}
fragment
=
Fragment
(
self
.
system
.
render_template
(
'videoannotation.html'
,
context
))
fragment
=
Fragment
(
self
.
system
.
render_template
(
'videoannotation.html'
,
context
))
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js"
)
fragment
.
add_javascript_url
(
"/static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js"
)
...
...
common/static/js/vendor/ova/OpenSeaDragonAnnotation.js
View file @
d2b26991
...
@@ -380,19 +380,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
...
@@ -380,19 +380,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
clickTimeThreshold
:
viewer
.
clickTimeThreshold
,
clickTimeThreshold
:
viewer
.
clickTimeThreshold
,
clickDistThreshold
:
viewer
.
clickDistThreshold
clickDistThreshold
:
viewer
.
clickDistThreshold
});
});
if
(
this
.
options
.
viewer
.
annotation_mode
==
"everyone"
||
this
.
options
.
viewer
.
flags
){
/* Set elements to the control menu */
/* Set elements to the control menu */
viewer
.
annotatorControl
=
viewer
.
wrapperAnnotation
.
element
;
viewer
.
annotatorControl
=
viewer
.
wrapperAnnotation
.
element
;
if
(
viewer
.
toolbar
){
if
(
viewer
.
toolbar
){
viewer
.
toolbar
.
addControl
(
viewer
.
toolbar
.
addControl
(
viewer
.
annotatorControl
,
viewer
.
annotatorControl
,
{
anchor
:
$
.
ControlAnchor
.
BOTTOM_RIGHT
}
{
anchor
:
$
.
ControlAnchor
.
BOTTOM_RIGHT
}
);
);
}
else
{
}
else
{
viewer
.
addControl
(
viewer
.
addControl
(
viewer
.
annotatorControl
,
viewer
.
annotatorControl
,
{
anchor
:
$
.
ControlAnchor
.
TOP_LEFT
}
{
anchor
:
$
.
ControlAnchor
.
TOP_LEFT
}
);
);
}
}
}
},
},
_reset
:
function
(){
_reset
:
function
(){
...
...
common/static/js/vendor/ova/catch/css/main.css
View file @
d2b26991
...
@@ -379,14 +379,14 @@
...
@@ -379,14 +379,14 @@
display
:
inline-block
;
display
:
inline-block
;
color
:
#302f2f
;
color
:
#302f2f
;
font-family
:
arial
;
font-family
:
arial
;
font-size
:
1
5
px
;
font-size
:
1
4
px
;
font-weight
:
bold
;
font-weight
:
bold
;
padding
:
6px
24px
;
padding
:
6px
24px
;
text-decoration
:
none
;
text-decoration
:
none
;
margin
:
0px
0px
10px
0px
;
margin
:
0px
0px
10px
0px
;
cursor
:
pointer
;
cursor
:
pointer
;
width
:
1
40
px
;
width
:
1
15
px
;
text-align
:
center
;
text-align
:
center
;
}
}
...
@@ -468,7 +468,7 @@
...
@@ -468,7 +468,7 @@
#mainCatch
.searchbox
input
{
#mainCatch
.searchbox
input
{
margin
:
0
;
margin
:
0
;
padding
:
0
;
padding
:
0
;
width
:
6
0%
;
width
:
5
0%
;
margin-left
:
10px
;
margin-left
:
10px
;
display
:
inline
;
display
:
inline
;
float
:
left
;
float
:
left
;
...
@@ -493,19 +493,28 @@
...
@@ -493,19 +493,28 @@
cursor
:
pointer
;
cursor
:
pointer
;
}
}
#mainCatch
.searchbox
.clear-search-icon
{
font-size
:
12px
;
text-decoration
:
underline
;
float
:
right
;
margin-top
:
10px
;
padding-right
:
3px
;
cursor
:
pointer
;
}
#mainCatch
.searchbox
.search-icon
:hover
{
#mainCatch
.searchbox
.search-icon
:hover
{
opacity
:
0.5
;
opacity
:
0.5
;
box-shadow
:
2px
4px
5px
#888888
;
box-shadow
:
2px
4px
5px
#888888
;
}
}
#mainCatch
.selectors
{
#mainCatch
.selectors
{
width
:
4
0
%
;
width
:
4
5
%
;
position
:
relative
;
position
:
relative
;
float
:
left
;
float
:
left
;
}
}
#mainCatch
.searchbox
{
#mainCatch
.searchbox
{
width
:
60
%
;
width
:
52
%
;
position
:
relative
;
position
:
relative
;
float
:
right
;
float
:
right
;
}
}
...
@@ -515,6 +524,7 @@
...
@@ -515,6 +524,7 @@
position
:
relative
;
position
:
relative
;
padding-right
:
5px
;
padding-right
:
5px
;
margin-top
:
8px
;
margin-top
:
8px
;
font-size
:
14px
;
}
}
#mainCatch
.replies
.replyItem
.deleteReply
{
#mainCatch
.replies
.replyItem
.deleteReply
{
...
...
common/static/js/vendor/ova/catch/js/catch.js
View file @
d2b26991
...
@@ -42,29 +42,29 @@ annotationList:
...
@@ -42,29 +42,29 @@ annotationList:
'</div>'
+
'</div>'
+
'<div class="annotatedBy field">'
+
'<div class="annotatedBy field">'
+
'User'
+
gettext
(
'User'
)
+
'</div>'
+
'</div>'
+
'<div class="body field">'
+
'<div class="body field">'
+
'Annotation'
+
gettext
(
'Annotation'
)
+
'</div>'
+
'</div>'
+
'{{#if videoFormat}}'
+
'{{#if videoFormat}}'
+
'<div class="start field">'
+
'<div class="start field">'
+
'Start'
+
gettext
(
'Start'
)
+
'</div>'
+
'</div>'
+
'<div class="end field">'
+
'<div class="end field">'
+
'End'
+
gettext
(
'End'
)
+
'</div>'
+
'</div>'
+
'{{/if}}'
+
'{{/if}}'
+
'<div class="totalreplies field">'
+
'<div class="totalreplies field">'
+
'#Replies'
+
gettext
(
'#Replies'
)
+
'</div>'
+
'</div>'
+
'<div class="annotatedAt field">'
+
'<div class="annotatedAt field">'
+
'Date posted'
+
gettext
(
'Date posted'
)
+
'</div>'
+
'</div>'
+
'</div>'
+
'</div>'
+
'</div>'
+
'</div>'
+
...
@@ -73,30 +73,41 @@ annotationList:
...
@@ -73,30 +73,41 @@ annotationList:
'{{/each}}'
+
'{{/each}}'
+
'</div>'
+
'</div>'
+
'<div class="annotationListButtons">'
+
'<div class="annotationListButtons">'
+
'<div class="moreButtonCatch">
More
</div>'
+
'<div class="moreButtonCatch">
'
+
gettext
(
'More'
)
+
'
</div>'
+
'</div>'
,
'</div>'
,
//Main->PublicPrivateInstructor
annotationPublicPrivateInstructor
:
'<div class="selectors"><div class="PublicPrivate myNotes active">'
+
gettext
(
'My Notes'
)
+
'<span class="action">myNotes</span></div>'
+
'<div class="PublicPrivate instructor"> '
+
gettext
(
'Instructor'
)
+
'<span class="action">instructor</span></div>'
+
'<div class="PublicPrivate public"> '
+
gettext
(
'Public'
)
+
'<span class="action">public</span></div></div>'
+
'<div class="searchbox"><div class="searchinst">'
+
gettext
(
'Search'
)
+
'</div><select class="dropdown-list">'
+
'<option>'
+
gettext
(
'Users'
)
+
'</option>'
+
'<option>'
+
gettext
(
'Tags'
)
+
'</option>'
+
'<option>'
+
gettext
(
'Annotation Text'
)
+
'</option>'
+
'</select><input type="text" name="search"/><div class="search-icon" alt="Run search."></div><div class="clear-search-icon" alt="Clear search.">'
+
gettext
(
'Clear'
)
+
'</div></div>'
,
//Main->PublicPrivate
//Main->PublicPrivate
annotationPublicPrivate
:
annotationPublicPrivate
:
'<div class="selectors"><div class="PublicPrivate myNotes active">
My Notes
<span class="action">myNotes</span></div>'
+
'<div class="selectors"><div class="PublicPrivate myNotes active">
'
+
gettext
(
'My Notes'
)
+
'
<span class="action">myNotes</span></div>'
+
'<div class="PublicPrivate public">
Public
<span class="action">public</span></div></div>'
+
'<div class="PublicPrivate public">
'
+
gettext
(
'Public'
)
+
'
<span class="action">public</span></div></div>'
+
'<div class="searchbox"><div class="searchinst">
Search
</div><select class="dropdown-list">'
+
'<div class="searchbox"><div class="searchinst">
'
+
gettext
(
'Search'
)
+
'
</div><select class="dropdown-list">'
+
'<option>
Users
</option>'
+
'<option>
'
+
gettext
(
'Users'
)
+
'
</option>'
+
'<option>
Tags
</option>'
+
'<option>
'
+
gettext
(
'Tags'
)
+
'
</option>'
+
'<option>
Annotation Text
</option>'
+
'<option>
'
+
gettext
(
'Annotation Text'
)
+
'
</option>'
+
'</select><input type="text" name="search"/><div class="search-icon" alt="Run search."></div></div>'
,
'</select><input type="text" name="search"/><div class="search-icon" alt="Run search."></div><
div class="clear-search-icon" alt="Clear search.">'
+
gettext
(
'Clear'
)
+
'</div><
/div>'
,
//Main->MediaSelector
//Main->MediaSelector
annotationMediaSelector
:
annotationMediaSelector
:
'<ul class="ui-tabs-nav">'
+
'<ul class="ui-tabs-nav">'
+
'<li class="ui-state-default" media="text">'
+
'<li class="ui-state-default" media="text">'
+
'Text'
+
gettext
(
'Text'
)
+
'</li>'
+
'</li>'
+
'<li class="ui-state-default" media="video">'
+
'<li class="ui-state-default" media="video">'
+
'Video'
+
gettext
(
'Video'
)
+
'</li>'
+
'</li>'
+
'li class="ui-state-default" media="image">'
+
'
<
li class="ui-state-default" media="image">'
+
'Image'
+
gettext
(
'Image'
)
+
'</li>'
+
'</li>'
+
'</ul>'
,
'</ul>'
,
...
@@ -126,7 +137,7 @@ annotationReply:
...
@@ -126,7 +137,7 @@ annotationReply:
'<div class="map"></div>'
+
'<div class="map"></div>'
+
'</div>'
+
'</div>'
+
'{{/if}}'
+
'{{/if}}'
+
'<div class="deleteReply">
Delete
</div>'
+
'<div class="deleteReply">
'
+
gettext
(
'Delete'
)
+
'
</div>'
+
'</p>'
+
'</p>'
+
'<p>'
+
'<p>'
+
'{{#if this.text}}'
+
'{{#if this.text}}'
+
...
@@ -233,13 +244,13 @@ annotationDetail:
...
@@ -233,13 +244,13 @@ annotationDetail:
'</div>'
+
'</div>'
+
'<div class="controlReplies">'
+
'<div class="controlReplies">'
+
'<div class="newReply" style="text-decoration:underline">
Reply
</div> '
+
'<div class="newReply" style="text-decoration:underline">
'
+
gettext
(
'Reply'
)
+
'
</div> '
+
'<div class="hideReplies" style="text-decoration:underline;display:{{#if hasReplies}}block{{else}}none{{/if}}">Show Replies</div> '
+
'<div class="hideReplies" style="text-decoration:underline;display:{{#if hasReplies}}block{{else}}none{{/if}}">Show Replies</div> '
+
'{{#if authToEditButton}}'
+
'{{#if authToEditButton}}'
+
'<div class="editAnnotation" style="text-decoration:underline">
Edit
</div>'
+
'<div class="editAnnotation" style="text-decoration:underline">
'
+
gettext
(
'Edit'
)
+
'
</div>'
+
'{{/if}}'
+
'{{/if}}'
+
'{{#if authToDeleteButton}}'
+
'{{#if authToDeleteButton}}'
+
'<div class="deleteAnnotation" style="text-decoration:underline">
Delete
</div>'
+
'<div class="deleteAnnotation" style="text-decoration:underline">
'
+
gettext
(
'Delete'
)
+
'
</div>'
+
'{{/if}}'
+
'{{/if}}'
+
'</div>'
+
'</div>'
+
...
@@ -248,7 +259,7 @@ annotationDetail:
...
@@ -248,7 +259,7 @@ annotationDetail:
'{{#if tags}}'
+
'{{#if tags}}'
+
'<div class="tags">'
+
'<div class="tags">'
+
'<h3>
Tags:
</h3>'
+
'<h3>
'
+
gettext
(
'Tags:'
)
+
'
</h3>'
+
'{{#each tags}}'
+
'{{#each tags}}'
+
'<div class="tag">'
+
'<div class="tag">'
+
'{{this}}'
+
'{{this}}'
+
...
@@ -290,14 +301,14 @@ CatchAnnotation = function (element, options) {
...
@@ -290,14 +301,14 @@ CatchAnnotation = function (element, options) {
//Reset element an create a new element div
//Reset element an create a new element div
element
.
html
(
'<div id="mainCatch" class="annotationListContainer"></div>'
);
element
.
html
(
'<div id="mainCatch" class="annotationListContainer"></div>'
);
this
.
current_tab
=
this
.
options
.
default_tab
;
//INIT
//INIT
var
self
=
this
;
var
self
=
this
;
$
(
document
).
ready
(
function
()
{
$
(
document
).
ready
(
function
()
{
self
.
init
();
self
.
init
();
self
.
refreshCatch
(
true
);
self
.
refreshCatch
(
true
);
var
moreBut
=
self
.
element
.
find
(
'.annotationListButtons .moreButtonCatch'
);
var
moreBut
=
self
.
element
.
find
(
'.annotationListButtons .moreButtonCatch'
);
moreBut
.
hide
();
moreBut
.
hide
();
});
});
return
this
;
return
this
;
...
@@ -310,6 +321,7 @@ CatchAnnotation.prototype = {
...
@@ -310,6 +321,7 @@ CatchAnnotation.prototype = {
this
.
TEMPLATENAMES
=
[
this
.
TEMPLATENAMES
=
[
"annotationList"
,
//Main
"annotationList"
,
//Main
"annotationPublicPrivate"
,
//Main->PublicPrivate
"annotationPublicPrivate"
,
//Main->PublicPrivate
"annotationPublicPrivateInstructor"
,
//Main->PublicPrivateInstructor
"annotationMediaSelector"
,
//Main->MediaSelector
"annotationMediaSelector"
,
//Main->MediaSelector
"annotationItem"
,
//Main->ContainerRow
"annotationItem"
,
//Main->ContainerRow
"annotationReply"
,
//Main->ContainerRow->Reply
"annotationReply"
,
//Main->ContainerRow->Reply
...
@@ -317,8 +329,8 @@ CatchAnnotation.prototype = {
...
@@ -317,8 +329,8 @@ CatchAnnotation.prototype = {
"annotationDetail"
,
//Main->ContainerRow->DetailRow
"annotationDetail"
,
//Main->ContainerRow->DetailRow
];
];
//annotator
//annotator
var
wrapper
=
$
(
'.annotator-wrapper'
).
parent
()[
0
]
,
var
wrapper
=
$
(
'.annotator-wrapper'
).
parent
()[
0
]
;
annotator
=
$
.
data
(
wrapper
,
'annotator'
);
var
annotator
=
$
.
data
(
wrapper
,
'annotator'
);
this
.
annotator
=
annotator
;
this
.
annotator
=
annotator
;
//Subscribe to annotator
//Subscribe to annotator
...
@@ -336,10 +348,22 @@ CatchAnnotation.prototype = {
...
@@ -336,10 +348,22 @@ CatchAnnotation.prototype = {
this
.
HTMLTEMPLATES
=
CatchSources
.
HTMLTEMPLATES
(
this
.
options
.
imageUrlRoot
);
this
.
HTMLTEMPLATES
=
CatchSources
.
HTMLTEMPLATES
(
this
.
options
.
imageUrlRoot
);
this
.
TEMPLATES
=
{};
this
.
TEMPLATES
=
{};
this
.
_compileTemplates
();
this
.
_compileTemplates
();
// the default annotations are the user's personal ones instead of instructor
// if the default tab is instructor, we must refresh the catch to pull the ones
// under the instructor's email. passing empty strings as arguments will default
// to pulling the annotations for the email within this.options.userId.
if
(
this
.
options
.
default_tab
.
toLowerCase
()
==
'instructor'
){
this
.
options
.
userId
=
this
.
options
.
instructor_email
;
this
.
_refresh
(
''
,
''
);
}
},
},
//
//
// GLOBAL UTILITIES
// GLOBAL UTILITIES
//
//
getTemplate
:
function
(
templateName
){
return
this
.
TEMPLATES
[
templateName
]()
||
''
;
},
refreshCatch
:
function
(
newInstance
)
{
refreshCatch
:
function
(
newInstance
)
{
var
mediaType
=
this
.
options
.
media
||
'text'
,
var
mediaType
=
this
.
options
.
media
||
'text'
,
annotationItems
=
[],
annotationItems
=
[],
...
@@ -380,10 +404,16 @@ CatchAnnotation.prototype = {
...
@@ -380,10 +404,16 @@ CatchAnnotation.prototype = {
if
(
newInstance
){
if
(
newInstance
){
var
videoFormat
=
(
mediaType
===
"video"
)
?
true
:
false
;
var
videoFormat
=
(
mediaType
===
"video"
)
?
true
:
false
;
var
publicPrivateTemplate
=
''
;
if
(
self
.
options
.
showPublicPrivate
)
{
var
templateName
=
this
.
options
.
instructor_email
?
"annotationPublicPrivateInstructor"
:
"annotationPublicPrivate"
;
}
el
.
html
(
self
.
TEMPLATES
.
annotationList
({
el
.
html
(
self
.
TEMPLATES
.
annotationList
({
annotationItems
:
annotationItems
,
annotationItems
:
annotationItems
,
videoFormat
:
videoFormat
,
videoFormat
:
videoFormat
,
PublicPrivate
:
self
.
options
.
showPublicPrivate
?
self
.
TEMPLATES
.
annotationPublicPrivate
():
''
,
PublicPrivate
:
this
.
getTemplate
(
templateName
)
,
MediaSelector
:
self
.
options
.
showMediaSelector
?
self
.
TEMPLATES
.
annotationMediaSelector
():
''
,
MediaSelector
:
self
.
options
.
showMediaSelector
?
self
.
TEMPLATES
.
annotationMediaSelector
():
''
,
}));
}));
}
else
{
}
else
{
...
@@ -402,10 +432,21 @@ CatchAnnotation.prototype = {
...
@@ -402,10 +432,21 @@ CatchAnnotation.prototype = {
//Set PublicPrivate
//Set PublicPrivate
var
PublicPrivateButtons
=
el
.
find
(
'.annotationListButtons .PublicPrivate'
).
removeClass
(
'active'
);
//reset
var
PublicPrivateButtons
=
el
.
find
(
'.annotationListButtons .PublicPrivate'
).
removeClass
(
'active'
);
//reset
for
(
var
index
=
0
;
index
<
PublicPrivateButtons
.
length
;
index
++
)
{
for
(
var
index
=
0
;
index
<
PublicPrivateButtons
.
length
;
index
++
)
{
var
span
=
$
(
PublicPrivateButtons
[
index
]).
find
(
'span'
),
var
span
=
$
(
PublicPrivateButtons
[
index
]).
find
(
'span'
);
isUser
=
(
typeof
self
.
options
.
userId
!=
'undefined'
&&
self
.
options
.
userId
!=
''
&&
self
.
options
.
userId
!=
null
);
if
(
span
.
html
().
toLowerCase
()
==
self
.
current_tab
.
toLowerCase
())
{
if
(
isUser
&&
span
.
html
()
==
"myNotes"
)
$
(
PublicPrivateButtons
[
index
]).
addClass
(
'active'
);
switch
(
self
.
current_tab
.
toLowerCase
()){
else
if
(
!
isUser
&&
span
.
html
()
==
"public"
)
$
(
PublicPrivateButtons
[
index
]).
addClass
(
'active'
);
case
'public'
:
self
.
options
.
userId
=
''
;
break
;
case
'instructor'
:
self
.
options
.
userId
=
this
.
options
.
instructor_email
;
break
;
default
:
self
.
options
.
userId
=
this
.
annotator
.
plugins
.
Permissions
.
user
.
id
;
break
;
}
$
(
PublicPrivateButtons
[
index
]).
addClass
(
'active'
);
}
}
}
//reset all old events
//reset all old events
...
@@ -423,6 +464,7 @@ CatchAnnotation.prototype = {
...
@@ -423,6 +464,7 @@ CatchAnnotation.prototype = {
onControlRepliesClick
=
this
.
__bind
(
this
.
_onControlRepliesClick
,
this
),
onControlRepliesClick
=
this
.
__bind
(
this
.
_onControlRepliesClick
,
this
),
onMoreButtonClick
=
this
.
__bind
(
this
.
_onMoreButtonClick
,
this
),
onMoreButtonClick
=
this
.
__bind
(
this
.
_onMoreButtonClick
,
this
),
onSearchButtonClick
=
this
.
__bind
(
this
.
_onSearchButtonClick
,
this
),
onSearchButtonClick
=
this
.
__bind
(
this
.
_onSearchButtonClick
,
this
),
onClearSearchButtonClick
=
this
.
__bind
(
this
.
_onClearSearchButtonClick
,
this
),
onDeleteReplyButtonClick
=
this
.
__bind
(
this
.
_onDeleteReplyButtonClick
,
this
),
onDeleteReplyButtonClick
=
this
.
__bind
(
this
.
_onDeleteReplyButtonClick
,
this
),
onZoomToImageBoundsButtonClick
=
this
.
__bind
(
this
.
_onZoomToImageBoundsButtonClick
,
this
);
onZoomToImageBoundsButtonClick
=
this
.
__bind
(
this
.
_onZoomToImageBoundsButtonClick
,
this
);
...
@@ -463,6 +505,9 @@ CatchAnnotation.prototype = {
...
@@ -463,6 +505,9 @@ CatchAnnotation.prototype = {
//Search Button
//Search Button
el
.
on
(
"click"
,
".searchbox .search-icon"
,
onSearchButtonClick
);
el
.
on
(
"click"
,
".searchbox .search-icon"
,
onSearchButtonClick
);
//Clear Search Button
el
.
on
(
"click"
,
".searchbox .clear-search-icon"
,
onClearSearchButtonClick
);
//Delete Reply Button
//Delete Reply Button
el
.
on
(
"click"
,
".replies .replyItem .deleteReply"
,
onDeleteReplyButtonClick
);
el
.
on
(
"click"
,
".replies .replyItem .deleteReply"
,
onDeleteReplyButtonClick
);
...
@@ -471,16 +516,16 @@ CatchAnnotation.prototype = {
...
@@ -471,16 +516,16 @@ CatchAnnotation.prototype = {
changeMedia
:
function
(
media
)
{
changeMedia
:
function
(
media
)
{
var
media
=
media
||
'text'
;
var
media
=
media
||
'text'
;
this
.
options
.
media
=
media
;
this
.
options
.
media
=
media
;
this
.
_refresh
();
this
.
_refresh
();
this
.
refreshCatch
(
true
);
this
.
refreshCatch
(
true
);
this
.
checkTotAnnotations
();
this
.
checkTotAnnotations
();
},
},
changeUserId
:
function
(
userId
)
{
changeUserId
:
function
(
userId
)
{
var
userId
=
userId
||
''
;
var
userId
=
userId
||
''
;
this
.
options
.
userId
=
userId
;
this
.
options
.
userId
=
userId
;
this
.
_refresh
();
this
.
_refresh
();
this
.
refreshCatch
(
true
);
this
.
refreshCatch
(
true
);
this
.
checkTotAnnotations
();
this
.
checkTotAnnotations
();
},
},
loadAnnotations
:
function
()
{
loadAnnotations
:
function
()
{
var
annotator
=
this
.
annotator
,
var
annotator
=
this
.
annotator
,
...
@@ -568,21 +613,26 @@ CatchAnnotation.prototype = {
...
@@ -568,21 +613,26 @@ CatchAnnotation.prototype = {
var
annotations
=
annotator
.
plugins
[
'Store'
].
annotations
,
var
annotations
=
annotator
.
plugins
[
'Store'
].
annotations
,
tot
=
typeof
annotations
!=
'undefined'
?
annotations
.
length
:
0
,
tot
=
typeof
annotations
!=
'undefined'
?
annotations
.
length
:
0
,
attempts
=
0
;
// max 100
attempts
=
0
;
// max 100
if
(
annotation
.
media
==
"image"
){
self
.
refreshCatch
(
true
);
self
.
checkTotAnnotations
();
}
else
{
//This is to watch the annotations object, to see when is deleted the annotation
//This is to watch the annotations object, to see when is deleted the annotation
var
ischanged
=
function
(){
var
ischanged
=
function
(){
var
new_tot
=
annotator
.
plugins
[
'Store'
].
annotations
.
length
;
var
new_tot
=
annotator
.
plugins
[
'Store'
].
annotations
.
length
;
if
(
attempts
<
100
)
if
(
attempts
<
100
)
setTimeout
(
function
(){
setTimeout
(
function
(){
if
(
new_tot
!=
tot
){
if
(
new_tot
!=
tot
){
self
.
refreshCatch
(
true
);
self
.
refreshCatch
(
true
);
self
.
checkTotAnnotations
();
self
.
checkTotAnnotations
();
}
else
{
}
else
{
attempts
++
;
attempts
++
;
ischanged
();
ischanged
();
}
}
},
100
);
//wait for the change in the annotations
},
100
);
//wait for the change in the annotations
};
};
ischanged
();
ischanged
();
}
});
});
annotator
.
subscribe
(
"annotationCreated"
,
function
(
annotation
){
annotator
.
subscribe
(
"annotationCreated"
,
function
(
annotation
){
var
attempts
=
0
;
// max 100
var
attempts
=
0
;
// max 100
...
@@ -770,6 +820,10 @@ CatchAnnotation.prototype = {
...
@@ -770,6 +820,10 @@ CatchAnnotation.prototype = {
var
allannotations
=
this
.
annotator
.
plugins
[
'Store'
].
annotations
,
var
allannotations
=
this
.
annotator
.
plugins
[
'Store'
].
annotations
,
osda
=
this
.
annotator
.
osda
;
osda
=
this
.
annotator
.
osda
;
if
(
this
.
options
.
externalLink
){
uri
+=
(
uri
.
indexOf
(
'?'
)
>=
0
)?
'&osdaId='
+
osdaId
:
'?osdaId='
+
osdaId
;
location
.
href
=
uri
;
}
for
(
var
item
in
allannotations
){
for
(
var
item
in
allannotations
){
var
an
=
allannotations
[
item
];
var
an
=
allannotations
[
item
];
if
(
typeof
an
.
id
!=
'undefined'
&&
an
.
id
==
osdaId
){
//this is the annotation
if
(
typeof
an
.
id
!=
'undefined'
&&
an
.
id
==
osdaId
){
//this is the annotation
...
@@ -1011,8 +1065,18 @@ CatchAnnotation.prototype = {
...
@@ -1011,8 +1065,18 @@ CatchAnnotation.prototype = {
userId
=
''
;
userId
=
''
;
//Get userI
//Get userI
userId
=
(
action
.
html
()
==
"myNotes"
)?
this
.
annotator
.
plugins
.
Permissions
.
user
.
id
:
''
;
switch
(
action
.
html
()){
case
'public'
:
userId
=
''
;
break
;
case
'instructor'
:
userId
=
this
.
options
.
instructor_email
;
break
;
default
:
userId
=
this
.
annotator
.
plugins
.
Permissions
.
user
.
id
;
break
;
}
this
.
current_tab
=
action
.
html
();
//Change userid and refresh
//Change userid and refresh
this
.
changeUserId
(
userId
);
this
.
changeUserId
(
userId
);
},
},
...
@@ -1069,6 +1133,9 @@ CatchAnnotation.prototype = {
...
@@ -1069,6 +1133,9 @@ CatchAnnotation.prototype = {
this
.
_refresh
(
searchtype
,
searchInput
);
this
.
_refresh
(
searchtype
,
searchInput
);
},
},
_onClearSearchButtonClick
:
function
(
evt
){
this
.
_refresh
(
''
,
''
);
},
_clearAnnotator
:
function
(){
_clearAnnotator
:
function
(){
var
annotator
=
this
.
annotator
,
var
annotator
=
this
.
annotator
,
store
=
annotator
.
plugins
.
Store
,
store
=
annotator
.
plugins
.
Store
,
...
...
lms/djangoapps/notes/views.py
View file @
d2b26991
from
django.contrib.auth.decorators
import
login_required
from
django.contrib.auth.decorators
import
login_required
from
django.http
import
Http404
from
django.http
import
Http404
from
edxmako.shortcuts
import
render_to_response
from
edxmako.shortcuts
import
render_to_response
from
opaque_keys.edx.locations
import
SlashSeparatedCourseKey
from
courseware.courses
import
get_course_with_access
from
courseware.courses
import
get_course_with_access
from
notes.models
import
Note
from
notes.models
import
Note
from
notes.utils
import
notes_enabled_for_course
from
notes.utils
import
notes_enabled_for_course
...
@@ -10,12 +11,12 @@ from xmodule.annotator_token import retrieve_token
...
@@ -10,12 +11,12 @@ from xmodule.annotator_token import retrieve_token
@login_required
@login_required
def
notes
(
request
,
course_id
):
def
notes
(
request
,
course_id
):
''' Displays the student's notes. '''
''' Displays the student's notes. '''
course_key
=
SlashSeparatedCourseKey
.
from_deprecated_string
(
course_id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_
id
)
course
=
get_course_with_access
(
request
.
user
,
'load'
,
course_
key
)
if
not
notes_enabled_for_course
(
course
):
if
not
notes_enabled_for_course
(
course
):
raise
Http404
raise
Http404
notes
=
Note
.
objects
.
filter
(
course_id
=
course_
id
,
user
=
request
.
user
)
.
order_by
(
'-created'
,
'uri'
)
notes
=
Note
.
objects
.
filter
(
course_id
=
course_
key
,
user
=
request
.
user
)
.
order_by
(
'-created'
,
'uri'
)
student
=
request
.
user
student
=
request
.
user
storage
=
course
.
annotation_storage_url
storage
=
course
.
annotation_storage_url
...
@@ -25,6 +26,7 @@ def notes(request, course_id):
...
@@ -25,6 +26,7 @@ def notes(request, course_id):
'student'
:
student
,
'student'
:
student
,
'storage'
:
storage
,
'storage'
:
storage
,
'token'
:
retrieve_token
(
student
.
email
,
course
.
annotation_token_secret
),
'token'
:
retrieve_token
(
student
.
email
,
course
.
annotation_token_secret
),
'default_tab'
:
'myNotes'
,
}
}
return
render_to_response
(
'notes.html'
,
context
)
return
render_to_response
(
'notes.html'
,
context
)
lms/templates/imageannotation.html
View file @
d2b26991
...
@@ -9,70 +9,69 @@
...
@@ -9,70 +9,69 @@
</style>
</style>
<div
class=
"annotatable-wrapper"
>
<div
class=
"annotatable-wrapper"
>
<div
class=
"annotatable-header"
>
<div
class=
"annotatable-header"
>
% if display_name is not UNDEFINED and display_name is not None:
% if display_name is not UNDEFINED and display_name is not None:
<div
class=
"annotatable-title"
>
${display_name}
</div>
<div
class=
"annotatable-title"
>
${display_name}
</div>
% endif
% endif
</div>
</div>
% if instructions_html is not UNDEFINED and instructions_html is not None:
% if instructions_html is not UNDEFINED and instructions_html is not None:
<div
class=
"annotatable-section shaded"
>
<div
class=
"annotatable-section shaded"
>
<div
class=
"annotatable-section-title"
>
<div
class=
"annotatable-section-title"
>
${_('Instructions')}
${_('Instructions')}
<a
class=
"annotatable-toggle annotatable-toggle-instructions expanded"
href=
"javascript:void(0)"
>
${_('Collapse Instructions')}
</a>
<a
class=
"annotatable-toggle annotatable-toggle-instructions expanded"
href=
"javascript:void(0)"
>
${_('Collapse Instructions')}
</a>
</div>
</div>
<div
class=
"annotatable-section-body annotatable-instructions"
>
<div
class=
"annotatable-section-body annotatable-instructions"
>
${instructions_html}
${instructions_html}
</div>
</div>
</div>
</div>
% endif
% endif
<div
class=
"annotatable-section"
>
<div
class=
"annotatable-section"
>
<div
class=
"annotatable-content"
>
<div
class=
"annotatable-content"
>
<div
id=
"imageHolder"
class=
"openseadragon1"
>
<div
id=
"imageHolder"
class=
"openseadragon1"
>
<
%
namespace
name=
'static'
file=
'/static_content.html'
/>
<
%
namespace
name=
'static'
file=
'/static_content.html'
/>
${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)}
</div>
</div>
<div
id=
"catchDIV"
>
<div
id=
"catchDIV"
>
## Translators: Notes below refer to annotations. They wil later be put under a "Notes" section.
<div
class=
"annotationListContainer"
>
${_('Note: only instructors may annotate.')}
</div>
<div
class=
"annotationListContainer"
>
${_('You do not have any notes.')}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
<script>
function
onClickHideInstructions
(){
function
onClickHideInstructions
(){
//Reset function if there is more than one event handler
//Reset function if there is more than one event handler
$
(
this
).
off
();
$
(
this
).
off
();
$
(
this
).
on
(
'click'
,
onClickHideInstructions
);
$
(
this
).
on
(
'click'
,
onClickHideInstructions
);
var
hide
=
$
(
this
).
html
()
==
'Collapse Instructions'
?
true
:
false
,
var
hide
=
$
(
this
).
html
()
==
'Collapse Instructions'
?
true
:
false
,
cls
,
txt
,
slideMethod
;
cls
,
txt
,
slideMethod
;
txt
=
(
hide
?
'Expand'
:
'Collapse'
)
+
' Instructions'
;
txt
=
(
hide
?
'Expand'
:
'Collapse'
)
+
' Instructions'
;
cls
=
(
hide
?
[
'expanded'
,
'collapsed'
]
:
[
'collapsed'
,
'expanded'
]);
cls
=
(
hide
?
[
'expanded'
,
'collapsed'
]
:
[
'collapsed'
,
'expanded'
]);
slideMethod
=
(
hide
?
'slideUp'
:
'slideDown'
);
slideMethod
=
(
hide
?
'slideUp'
:
'slideDown'
);
$
(
this
).
text
(
txt
).
removeClass
(
cls
[
0
]).
addClass
(
cls
[
1
]);
$
(
this
).
text
(
txt
).
removeClass
(
cls
[
0
]).
addClass
(
cls
[
1
]);
$
(
this
).
parents
(
'.annotatable-section:first'
).
find
(
'.annotatable-instructions'
)[
slideMethod
]();
$
(
this
).
parents
(
'.annotatable-section:first'
).
find
(
'.annotatable-instructions'
)[
slideMethod
]();
}
}
$
(
'.annotatable-toggle-instructions'
).
on
(
'click'
,
onClickHideInstructions
);
$
(
'.annotatable-toggle-instructions'
).
on
(
'click'
,
onClickHideInstructions
);
//Grab uri of the course
//Grab uri of the course
var
parts
=
window
.
location
.
href
.
split
(
"/"
),
var
parts
=
window
.
location
.
href
.
split
(
"/"
),
uri
=
''
,
uri
=
''
,
courseid
;
courseid
;
for
(
var
index
=
0
;
index
<=
9
;
index
+=
1
)
uri
+=
parts
[
index
]
+
"/"
;
//Get the unit url
for
(
var
index
=
0
;
index
<=
9
;
index
+=
1
)
uri
+=
parts
[
index
]
+
"/"
;
//Get the unit url
courseid
=
parts
[
4
]
+
"/"
+
parts
[
5
]
+
"/"
+
parts
[
6
];
courseid
=
parts
[
4
]
+
"/"
+
parts
[
5
]
+
"/"
+
parts
[
6
];
//Change uri in cms
//Change uri in cms
var
lms_location
=
$
(
'.sidebar .preview-button'
).
attr
(
'href'
);
var
lms_location
=
$
(
'.sidebar .preview-button'
).
attr
(
'href'
);
if
(
typeof
lms_location
!=
'undefined'
){
if
(
typeof
lms_location
!=
'undefined'
){
courseid
=
parts
[
4
].
split
(
"."
).
join
(
"/"
);
courseid
=
parts
[
4
].
split
(
"."
).
join
(
"/"
);
uri
=
window
.
location
.
protocol
;
uri
=
window
.
location
.
protocol
;
for
(
var
index
=
0
;
index
<=
9
;
index
+=
1
)
uri
+=
lms_location
.
split
(
"/"
)[
index
]
+
"/"
;
//Get the unit url
for
(
var
index
=
0
;
index
<=
9
;
index
+=
1
)
uri
+=
lms_location
.
split
(
"/"
)[
index
]
+
"/"
;
//Get the unit url
}
}
var
unit_id
=
$
(
'#sequence-list'
).
find
(
'.active'
).
attr
(
"data-element"
);
var
unit_id
=
$
(
'#sequence-list'
).
find
(
'.active'
).
attr
(
"data-element"
);
uri
+=
unit_id
;
uri
+=
unit_id
;
var
pagination
=
100
,
var
pagination
=
100
,
is_staff
=
!
(
'${user.is_staff}'
==
'False
'
),
is_staff
=
(
'${user.email}'
==
'${instructor_email}
'
),
options
=
{
options
=
{
optionsAnnotator
:
{
optionsAnnotator
:
{
permissions
:{
permissions
:{
...
@@ -103,7 +102,7 @@
...
@@ -103,7 +102,7 @@
if
(
annotation
.
permissions
)
{
if
(
annotation
.
permissions
)
{
tokens
=
annotation
.
permissions
[
action
]
||
[];
tokens
=
annotation
.
permissions
[
action
]
||
[];
if
(
is_staff
){
if
(
is_staff
){
return
true
;
return
true
;
}
}
if
(
tokens
.
length
===
0
)
{
if
(
tokens
.
length
===
0
)
{
return
true
;
return
true
;
...
@@ -153,7 +152,7 @@
...
@@ -153,7 +152,7 @@
offset
:
0
,
offset
:
0
,
uri
:
uri
,
uri
:
uri
,
media
:
'image'
,
media
:
'image'
,
userid
:
'${user.email}'
,
userid
:
'${user.email}'
,
}
}
},
},
highlightTags
:{
highlightTags
:{
...
@@ -172,6 +171,8 @@
...
@@ -172,6 +171,8 @@
},
},
optionsOpenSeadragon
:{
optionsOpenSeadragon
:{
id
:
"imageHolder"
,
id
:
"imageHolder"
,
annotation_mode
:
"${annotation_mode}"
,
flags
:
is_staff
,
prefixUrl
:
"${settings.STATIC_URL}"
+
"js/vendor/ova/images/"
,
prefixUrl
:
"${settings.STATIC_URL}"
+
"js/vendor/ova/images/"
,
$
{
openseadragonjson
}
$
{
openseadragonjson
}
},
},
...
@@ -179,29 +180,43 @@
...
@@ -179,29 +180,43 @@
};
};
var
imgURLRoot
=
"${settings.STATIC_URL}"
+
"js/vendor/ova/catch/img/"
;
var
imgURLRoot
=
"${settings.STATIC_URL}"
+
"js/vendor/ova/catch/img/"
;
if
(
typeof
Annotator
!=
'undefined'
){
if
(
typeof
Annotator
!=
'undefined'
){
//remove old instances
//remove old instances
if
(
Annotator
.
_instances
.
length
!==
0
)
{
if
(
Annotator
.
_instances
.
length
!==
0
)
{
$
(
'#imageHolder'
).
annotator
(
"destroy"
);
$
(
'#imageHolder'
).
annotator
(
"destroy"
);
}
}
delete
osda
;
delete
osda
;
//Load the plugin Image/Text Annotation
//Load the plugin Image/Text Annotation
var
osda
=
new
OpenSeadragonAnnotation
(
$
(
'#imageHolder'
),
options
);
var
osda
=
new
OpenSeadragonAnnotation
(
$
(
'#imageHolder'
),
options
);
//Catch
var
userId
=
(
'${default_tab}'
.
toLowerCase
()
===
'instructor'
)
?
var
annotator
=
osda
.
annotator
,
'${instructor_email}'
:
catchOptions
=
{
'${user.email}'
;
media
:
'image'
,
externalLink
:
false
,
//Catch
imageUrlRoot
:
imgURLRoot
,
var
annotator
=
osda
.
annotator
;
showMediaSelector
:
false
,
var
catchOptions
=
{
showPublicPrivate
:
true
,
media
:
'image'
,
userId
:
'${user.email}'
,
externalLink
:
false
,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
imageUrlRoot
:
imgURLRoot
,
flags
:
is_staff
showMediaSelector
:
false
,
},
showPublicPrivate
:
true
,
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
userId
:
userId
,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
flags
:
is_staff
,
default_tab
:
"${default_tab}"
,
instructor_email
:
"${instructor_email}"
,
annotation_mode
:
"${annotation_mode}"
,
};
// if annotations are opened to everyone (2) or if they want to create no annotations (1 with no instructor)
// then the table at the bottom of the source should be displayed
if
(
"${annotation_mode}"
==
"everyone"
||
(
"${annotation_mode}"
==
"instructor"
&&
"${instructor_email}"
!=
""
))
var
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
// if it is in instructor mode only (1), the annotator should be destroyed for all except the instructor
if
(
"${annotation_mode}"
==
"instructor"
&&
"${instructor_email}"
==
""
&&
!
is_staff
)
osda
.
annotator
.
destroy
();
}
}
</script>
</script>
\ No newline at end of file
lms/templates/notes.html
View file @
d2b26991
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%!
from
django
.
utils
.
translation
import
ugettext
as
_
%
>
<
%
namespace
name=
'static'
file=
'static_content.html'
/>
<
%
namespace
name=
'static'
file=
'static_content.html'
/>
${static.css(group='style-vendor-tinymce-content', raw=True)}
${static.css(group='style-vendor-tinymce-skin', raw=True)}
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/tinymce/js/tinymce/tinymce.full.min.js', raw=True)}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', raw=True)}"
></script>
<
%
inherit
file=
"main.html"
/>
<
%
inherit
file=
"main.html"
/>
<
%!
<
%!
from
django
.
core
.
urlresolvers
import
reverse
from
django
.
core
.
urlresolvers
import
reverse
...
@@ -102,7 +106,7 @@
...
@@ -102,7 +106,7 @@
if
(
annotation
.
permissions
)
{
if
(
annotation
.
permissions
)
{
tokens
=
annotation
.
permissions
[
action
]
||
[];
tokens
=
annotation
.
permissions
[
action
]
||
[];
if
(
is_staff
){
if
(
is_staff
){
return
true
;
return
true
;
}
}
if
(
tokens
.
length
===
0
)
{
if
(
tokens
.
length
===
0
)
{
return
true
;
return
true
;
...
@@ -128,7 +132,7 @@
...
@@ -128,7 +132,7 @@
},
},
},
},
auth
:
{
auth
:
{
token
Url
:
location
.
protocol
+
'//'
+
location
.
host
+
"/token?course_id=${course.id.to_deprecated_string()
}"
token
:
"${token
}"
},
},
store
:
{
store
:
{
// The endpoint of the store on your server.
// The endpoint of the store on your server.
...
@@ -158,37 +162,34 @@
...
@@ -158,37 +162,34 @@
optionsRichText
:
{
optionsRichText
:
{
tinymce
:{
tinymce
:{
selector
:
"li.annotator-item textarea"
,
selector
:
"li.annotator-item textarea"
,
plugins
:
"media image
insertdatetime link code
"
,
plugins
:
"media image
codemirror
"
,
menubar
:
false
,
menubar
:
false
,
toolbar_items_size
:
'small'
,
toolbar_items_size
:
'small'
,
extended_valid_elements
:
"iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]"
,
extended_valid_elements
:
"iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]"
,
toolbar
:
"insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent |
link image media
rubric | code "
,
toolbar
:
"insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent |
image
rubric | code "
,
}
}
return
true
;
},
},
auth
:
{
token
:
"${token}"
},
store
:
{
// The endpoint of the store on your server.
prefix
:
"${storage}"
,
annotationData
:
{},
urls
:
{
// These are the default URLs.
create
:
'/create'
,
read
:
'/read/:id'
,
update
:
'/update/:id'
,
destroy
:
'/delete/:id'
,
search
:
'/search'
},
},
auth
:
{
token
:
"${token}"
},
store
:
{
// The endpoint of the store on your server.
prefix
:
"${storage}"
,
annotationData
:
{},
urls
:
{
// These are the default URLs.
create
:
'/create'
,
read
:
'/read/:id'
,
update
:
'/update/:id'
,
destroy
:
'/delete/:id'
,
search
:
'/search'
},
}
};
};
tinyMCE
.
baseURL
=
"${settings.STATIC_URL}"
+
"js/vendor/ova"
;
var
imgURLRoot
=
"${settings.STATIC_URL}"
+
"js/vendor/ova/catch/img/"
;
var
imgURLRoot
=
"${settings.STATIC_URL}"
+
"js/vendor/ova/catch/img/"
;
//remove old instances
//remove old instances
if
(
Annotator
.
_instances
.
length
!==
0
)
{
if
(
Annotator
.
_instances
.
length
!==
0
)
{
$
(
'#notesHolder'
).
annotator
(
"destroy"
);
$
(
'#notesHolder'
).
annotator
(
"destroy"
);
...
@@ -207,7 +208,8 @@
...
@@ -207,7 +208,8 @@
showMediaSelector
:
true
,
showMediaSelector
:
true
,
showPublicPrivate
:
true
,
showPublicPrivate
:
true
,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
flags
:
is_staff
flags
:
is_staff
,
default_tab
:
"${default_tab}"
,
},
},
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
</script>
</script>
...
...
lms/templates/textannotation.html
View file @
d2b26991
...
@@ -177,17 +177,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
...
@@ -177,17 +177,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
//Load the plugin Video/Text Annotation
//Load the plugin Video/Text Annotation
var
ova
=
new
OpenVideoAnnotation
.
Annotator
(
$
(
'#textHolder'
),
options
);
var
ova
=
new
OpenVideoAnnotation
.
Annotator
(
$
(
'#textHolder'
),
options
);
var
userId
=
(
'${default_tab}'
.
toLowerCase
()
===
'instructor'
)
?
'${instructor_email}'
:
'${user.email}'
;
//Catch
//Catch
var
annotator
=
ova
.
annotator
,
var
annotator
=
ova
.
annotator
;
catchOptions
=
{
var
catchOptions
=
{
media
:
'text'
,
media
:
'text'
,
externalLink
:
false
,
externalLink
:
false
,
imageUrlRoot
:
imgURLRoot
,
imageUrlRoot
:
imgURLRoot
,
showMediaSelector
:
false
,
showMediaSelector
:
false
,
showPublicPrivate
:
true
,
showPublicPrivate
:
true
,
userId
:
'${user.email}'
,
userId
:
userId
,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
flags
:
is_staff
flags
:
is_staff
,
},
default_tab
:
"${default_tab}"
,
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
instructor_email
:
"${instructor_email}"
,
annotation_mode
:
"${annotation_mode}"
,
};
var
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
</script>
</script>
lms/templates/videoannotation.html
View file @
d2b26991
...
@@ -175,18 +175,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
...
@@ -175,18 +175,24 @@ ${static.css(group='style-vendor-tinymce-skin', raw=True)}
var
ova
=
new
OpenVideoAnnotation
.
Annotator
(
$
(
'#videoHolder'
),
options
);
var
ova
=
new
OpenVideoAnnotation
.
Annotator
(
$
(
'#videoHolder'
),
options
);
ova
.
annotator
.
addPlugin
(
'Tags'
);
ova
.
annotator
.
addPlugin
(
'Tags'
);
var
userId
=
(
'${default_tab}'
.
toLowerCase
()
===
'instructor'
)
?
'${instructor_email}'
:
'${user.email}'
;
//Catch
//Catch
var
annotator
=
ova
.
annotator
,
var
annotator
=
ova
.
annotator
;
catchOptions
=
{
var
catchOptions
=
{
media
:
'video'
,
media
:
'video'
,
externalLink
:
false
,
externalLink
:
false
,
imageUrlRoot
:
imgURLRoot
,
imageUrlRoot
:
imgURLRoot
,
showMediaSelector
:
false
,
showMediaSelector
:
false
,
showPublicPrivate
:
true
,
showPublicPrivate
:
true
,
userId
:
'${user.email}'
,
userId
:
userId
,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
pagination
:
pagination
,
//Number of Annotations per load in the pagination,
flags
:
is_staff
flags
:
is_staff
,
},
default_tab
:
"${default_tab}"
,
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
instructor_email
:
"${instructor_email}"
,
annotation_mode
:
"${annotation_mode}"
,
};
var
Catch
=
new
CatchAnnotation
(
$
(
'#catchDIV'
),
catchOptions
);
</script>
</script>
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