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
7ed0002b
Commit
7ed0002b
authored
Nov 29, 2012
by
Don Mitchell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Details now has validation except for youtube ids which cause
crossdomain policy violations when i try to validate.
parent
c0da6e42
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
118 additions
and
16 deletions
+118
-16
cms/static/js/models/settings/course_details.js
+62
-3
cms/static/js/views/settings/main_settings_view.js
+56
-13
No files found.
cms/static/js/models/settings/course_details.js
View file @
7ed0002b
...
...
@@ -33,20 +33,57 @@ CMS.Models.Settings.CourseDetails = Backbone.Model.extend({
return
attributes
;
},
validate
:
function
(
newattrs
)
{
// Returns either nothing (no return call) so that validate works or an object of {field: errorstring} pairs
// A bit funny in that the video key validation is asynchronous; so, it won't stop the validation.
var
errors
=
{};
if
(
newattrs
.
start_date
&&
newattrs
.
end_date
&&
newattrs
.
start_date
>=
newattrs
.
end_date
)
{
errors
.
end_date
=
"The course end date cannot be before the course start date."
;
}
if
(
newattrs
.
start_date
&&
newattrs
.
enrollment_start
&&
newattrs
.
start_date
<
newattrs
.
enrollment_start
)
{
errors
.
enrollment_start
=
"The course start date cannot be before the enrollment start date."
;
}
if
(
newattrs
.
enrollment_start
&&
newattrs
.
enrollment_end
&&
newattrs
.
enrollment_start
>=
newattrs
.
enrollment_end
)
{
errors
.
enrollment_end
=
"The enrollment start date cannot be after the enrollment end date."
;
}
if
(
newattrs
.
end_date
&&
newattrs
.
enrollment_end
&&
newattrs
.
end_date
<
newattrs
.
enrollment_end
)
{
errors
.
enrollment_end
=
"The enrollment end date cannot be after the course end date."
;
}
if
(
newattrs
.
intro_video
&&
newattrs
.
intro_video
!=
this
.
get
(
'intro_video'
))
{
var
videos
=
this
.
parse_videosource
(
newattrs
.
intro_video
);
var
vid_errors
=
new
Array
();
var
cachethis
=
this
;
for
(
var
i
=
0
;
i
<
videos
.
length
;
i
++
)
{
// doesn't call parseFloat or Number b/c they stop on first non parsable and return what they have
if
(
!
isFinite
(
videos
[
i
].
speed
))
vid_errors
.
push
(
videos
[
i
].
speed
+
" is not a valid speed."
);
// can't use get from client to test if video exists b/c of CORS (crossbrowser get not allowed)
// GET "http://gdata.youtube.com/feeds/api/videos/" + videokey
}
if
(
!
_
.
isEmpty
(
vid_errors
))
{
errors
.
intro_video
=
vid_errors
.
join
(
'/n'
);
}
}
if
(
!
_
.
isEmpty
(
errors
))
return
errors
;
// NOTE don't return empty errors as that will be interpreted as an error state
},
urlRoot
:
function
()
{
var
location
=
this
.
get
(
'location'
);
return
'/'
+
location
.
get
(
'org'
)
+
"/"
+
location
.
get
(
'course'
)
+
'/settings/'
+
location
.
get
(
'name'
)
+
'/section/details'
;
},
_videoprefix
:
/
\s
*<video
\s
*youtube="/g
,
_videospeedparse
:
/
\d
+
\.?\d
*
(?=
:
)
/g
,
// the below is lax to enable validation
_videospeedparse
:
/
[^
:
]
*/g
,
// /\d+\.?\d*(?=:)/g,
_videokeyparse
:
/
([^
,
\/]
+
)
/g
,
_videonosuffix
:
/
[^\"]
+/g
,
_getNextMatch
:
function
(
regex
,
string
,
cursor
)
{
regex
.
lastIndex
=
cursor
;
return
regex
.
exec
(
string
);
var
result
=
regex
.
exec
(
string
);
if
(
_
.
isArray
(
result
))
return
result
[
0
];
else
return
result
;
},
// the whole string for editing
// the whole string for editing
(put in edit box)
getVideoSource
:
function
()
{
if
(
this
.
get
(
'intro_video'
))
{
var
cursor
=
0
;
...
...
@@ -95,10 +132,32 @@ CMS.Models.Settings.CourseDetails = Backbone.Model.extend({
else
return
""
;
}
},
parse_videosource
:
function
(
videostring
)
{
// used to validate before set so cannot get from model attr. Returns [{ speed: fff, key: sss }]
var
cursor
=
0
;
this
.
_getNextMatch
(
this
.
_videoprefix
,
videostring
,
cursor
);
cursor
=
this
.
_videoprefix
.
lastIndex
;
videostring
=
this
.
_getNextMatch
(
this
.
_videonosuffix
,
videostring
,
cursor
);
cursor
=
0
;
// parsed to "fff:kkk,fff:kkk"
var
result
=
new
Array
();
while
(
cursor
<
videostring
.
length
)
{
var
speed
=
this
.
_getNextMatch
(
this
.
_videospeedparse
,
videostring
,
cursor
);
if
(
speed
)
cursor
=
this
.
_videospeedparse
.
lastIndex
+
1
;
else
return
result
;
var
key
=
this
.
_getNextMatch
(
this
.
_videokeyparse
,
videostring
,
cursor
);
cursor
=
this
.
_videokeyparse
.
lastIndex
+
1
;
// See the WTF above
if
(
_
.
isArray
(
key
))
key
=
key
[
0
];
result
.
push
({
speed
:
speed
,
key
:
key
});
}
return
result
;
},
save_videosource
:
function
(
newsource
)
{
// newsource either is <video youtube="speed:key, *"/> or just the "speed:key, *" string
// returns the videosource for the preview which iss the key whose speed is closest to 1
if
(
newsource
==
null
)
this
.
save
({
'intro_video'
:
null
});
// TODO remove all whitespace w/in string
else
if
(
this
.
_getNextMatch
(
this
.
_videoprefix
,
newsource
,
0
))
this
.
save
(
'intro_video'
,
newsource
);
else
this
.
save
(
'intro_video'
,
'<video youtube="'
+
newsource
+
'"/>'
);
...
...
cms/static/js/views/settings/main_settings_view.js
View file @
7ed0002b
...
...
@@ -87,43 +87,85 @@ CMS.Views.Settings.Details = Backbone.View.extend({
initialize
:
function
()
{
// TODO move the html frag to a loaded asset
this
.
fileAnchorTemplate
=
_
.
template
(
'<a href="<%= fullpath %>"> <i class="ss-icon ss-standard">📄</i><%= filename %></a>'
);
this
.
errorTemplate
=
_
.
template
(
'<span class="message-error"><%= message %></span>'
);
this
.
model
.
on
(
'error'
,
this
.
handleValidationError
,
this
);
},
render
:
function
()
{
this
.
setupDatePicker
(
'
#course-start'
,
'start_date'
);
this
.
setupDatePicker
(
'
#course-end'
,
'end_date'
);
this
.
setupDatePicker
(
'
#enrollment-start'
,
'enrollment_start'
);
this
.
setupDatePicker
(
'
#enrollment-end'
,
'enrollment_end'
);
this
.
setupDatePicker
(
'
start_date'
)
this
.
setupDatePicker
(
'
end_date'
)
this
.
setupDatePicker
(
'
enrollment_start'
)
this
.
setupDatePicker
(
'
enrollment_end'
)
if
(
this
.
model
.
has
(
'syllabus'
))
{
this
.
$el
.
find
(
'.current-course-syllabus .doc-filename'
).
html
(
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
'syllabus'
]
).
html
(
this
.
fileAnchorTemplate
({
fullpath
:
this
.
model
.
get
(
'syllabus'
),
filename
:
'syllabus'
}));
this
.
$el
.
find
(
'.remove-course-syllabus'
).
show
();
}
else
{
this
.
$el
.
find
(
'.current-course-syllabus .doc-filename'
).
html
(
""
);
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
'syllabus'
]
).
html
(
""
);
this
.
$el
.
find
(
'.remove-course-syllabus'
).
hide
();
}
this
.
$el
.
find
(
'#course-overview'
).
val
(
this
.
model
.
get
(
'overview'
));
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
'overview'
]
).
val
(
this
.
model
.
get
(
'overview'
));
this
.
$el
.
find
(
'.current-course-introduction-video iframe'
).
attr
(
'src'
,
this
.
model
.
videosourceSample
());
if
(
this
.
model
.
has
(
'intro_video'
))
{
this
.
$el
.
find
(
'.remove-course-introduction-video'
).
show
();
this
.
$el
.
find
(
'#course-introduction-video'
).
val
(
this
.
model
.
getVideoSource
());
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
'intro_video'
]
).
val
(
this
.
model
.
getVideoSource
());
}
else
this
.
$el
.
find
(
'.remove-course-introduction-video'
).
hide
();
this
.
$el
.
find
(
"#course-effort"
).
val
(
this
.
model
.
get
(
'effort'
));
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
'effort'
]
).
val
(
this
.
model
.
get
(
'effort'
));
return
this
;
},
fieldToSelectorMap
:
{
'start_date'
:
"#course-start"
,
'end_date'
:
'#course-end'
,
'enrollment_start'
:
'#enrollment-start'
,
'enrollment_end'
:
'#enrollment-end'
,
'syllabus'
:
'.current-course-syllabus .doc-filename'
,
'overview'
:
'#course-overview'
,
'intro_video'
:
'#course-introduction-video'
,
'effort'
:
"#course-effort"
},
_cacheValidationErrors
:
null
,
handleValidationError
:
function
(
model
,
error
)
{
this
.
_cacheValidationErrors
=
error
;
// error is object w/ fields and error strings
for
(
var
field
in
error
)
{
var
ele
=
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
field
]);
if
(
$
(
ele
).
is
(
'div'
))
{
// put error on the contained inputs
$
(
ele
).
find
(
'input, textarea'
).
addClass
(
'error'
);
}
else
$
(
ele
).
addClass
(
'error'
);
$
(
ele
).
parent
().
append
(
this
.
errorTemplate
({
message
:
error
[
field
]}));
}
},
setupDatePicker
:
function
(
elementName
,
fieldName
)
{
clearValidationErrors
:
function
()
{
if
(
this
.
_cacheValidationErrors
==
null
)
return
;
// error is object w/ fields and error strings
for
(
var
field
in
this
.
_cacheValidationErrors
)
{
var
ele
=
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
field
]);
if
(
$
(
ele
).
is
(
'div'
))
{
// put error on the contained inputs
$
(
ele
).
find
(
'input, textarea'
).
removeClass
(
'error'
);
}
else
$
(
ele
).
removeClass
(
'error'
);
$
(
ele
).
nextAll
(
'.message-error'
).
remove
();
}
this
.
_cacheValidationErrors
=
null
;
},
setupDatePicker
:
function
(
fieldName
)
{
var
cacheModel
=
this
.
model
;
var
div
=
this
.
$el
.
find
(
elementName
);
var
div
=
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
fieldName
]
);
var
datefield
=
$
(
div
).
find
(
".date"
);
var
timefield
=
$
(
div
).
find
(
".time"
);
var
savefield
=
function
()
{
...
...
@@ -143,7 +185,8 @@ CMS.Views.Settings.Details = Backbone.View.extend({
},
updateModel
:
function
(
event
)
{
// figure out which field
this
.
clearValidationErrors
();
switch
(
event
.
currentTarget
.
id
)
{
case
'course-start-date'
:
// handled via onSelect method
case
'course-end-date'
:
...
...
@@ -181,7 +224,7 @@ CMS.Views.Settings.Details = Backbone.View.extend({
if
(
this
.
model
.
has
(
'intro_video'
))
{
this
.
model
.
save_videosource
(
null
);
this
.
$el
.
find
(
".current-course-introduction-video iframe"
).
attr
(
"src"
,
""
);
this
.
$el
.
find
(
'#course-introduction-video'
).
val
(
""
);
this
.
$el
.
find
(
this
.
fieldToSelectorMap
[
'intro_video'
]
).
val
(
""
);
}
}
...
...
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