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
9af447de
Commit
9af447de
authored
Jun 12, 2013
by
David Baumgold
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Moved Backbone models/views out to separate files for pdf textbooks project
parent
0d415d81
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
437 additions
and
435 deletions
+437
-435
cms/static/js/models/textbooks.js
+101
-0
cms/static/js/views/textbooks.js
+333
-0
cms/templates/textbooks.html
+3
-435
No files found.
cms/static/js/models/textbooks.js
0 → 100644
View file @
9af447de
CMS
.
Models
.
Textbook
=
Backbone
.
AssociatedModel
.
extend
({
defaults
:
function
()
{
return
{
name
:
""
,
chapters
:
new
CMS
.
Collections
.
ChapterSet
([{}]),
showChapters
:
false
};
},
relations
:
[{
type
:
Backbone
.
Many
,
key
:
"chapters"
,
relatedModel
:
"CMS.Models.Chapter"
,
collectionType
:
"CMS.Collections.ChapterSet"
}],
isEmpty
:
function
()
{
return
!
this
.
get
(
'name'
)
&&
this
.
get
(
'chapters'
).
isEmpty
();
},
parse
:
function
(
response
)
{
if
(
"tab_title"
in
response
&&
!
(
"name"
in
response
))
{
response
.
name
=
response
.
tab_title
;
delete
response
.
tab_title
;
}
if
(
"url"
in
response
&&
!
(
"chapters"
in
response
))
{
response
.
chapters
=
{
"url"
:
response
.
url
};
delete
response
.
url
;
}
_
.
each
(
response
.
chapters
,
function
(
chapter
,
i
)
{
chapter
.
order
=
chapter
.
order
||
i
+
1
;
});
return
response
;
},
toJSON
:
function
()
{
return
{
tab_title
:
this
.
get
(
'name'
),
chapters
:
this
.
get
(
'chapters'
).
toJSON
()
};
}
});
CMS
.
Collections
.
TextbookSet
=
Backbone
.
Collection
.
extend
({
model
:
CMS
.
Models
.
Textbook
,
url
:
function
()
{
return
window
.
TEXTBOOK_URL
;
},
initialize
:
function
()
{
this
.
listenTo
(
this
,
"editOne"
,
this
.
editOne
);
},
editOne
:
function
(
textbook
)
{
this
.
editing
=
textbook
;
},
save
:
function
(
options
)
{
return
this
.
sync
(
'update'
,
this
,
options
);
}
});
CMS
.
Models
.
Chapter
=
Backbone
.
AssociatedModel
.
extend
({
defaults
:
function
()
{
return
{
name
:
""
,
asset_path
:
""
,
order
:
this
.
collection
?
this
.
collection
.
nextOrder
()
:
1
};
},
isEmpty
:
function
()
{
return
!
this
.
get
(
'name'
)
&&
!
this
.
get
(
'asset_path'
);
},
parse
:
function
(
response
)
{
if
(
"title"
in
response
&&
!
(
"name"
in
response
))
{
response
.
name
=
response
.
title
;
delete
response
.
title
;
}
if
(
"url"
in
response
&&
!
(
"asset_path"
in
response
))
{
response
.
asset_path
=
response
.
url
;
delete
response
.
url
;
}
return
response
;
},
toJSON
:
function
()
{
return
{
title
:
this
.
get
(
'name'
),
url
:
this
.
get
(
'asset_path'
)
};
}
});
CMS
.
Collections
.
ChapterSet
=
Backbone
.
Collection
.
extend
({
model
:
CMS
.
Models
.
Chapter
,
comparator
:
"order"
,
nextOrder
:
function
()
{
if
(
!
this
.
length
)
return
1
;
return
this
.
last
().
get
(
'order'
)
+
1
;
},
isEmpty
:
function
()
{
return
this
.
length
===
0
||
this
.
every
(
function
(
m
)
{
return
m
.
isEmpty
();
});
}
});
CMS
.
Models
.
FileUpload
=
Backbone
.
Model
.
extend
({
defaults
:
{
"title"
:
""
,
"message"
:
""
,
"selectFile"
:
null
,
"uploading"
:
false
,
"uploadedBytes"
:
0
,
"totalBytes"
:
0
}
});
cms/static/js/views/textbooks.js
0 → 100644
View file @
9af447de
CMS
.
Views
.
TextbookShow
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#show-textbook-tpl"
).
text
());
this
.
listenTo
(
this
.
model
,
"change"
,
this
.
render
);
},
tagName
:
"li"
,
events
:
{
"click .edit"
:
"editTextbook"
,
"click .delete"
:
"confirmDelete"
,
"click .show-chapters"
:
"showChapters"
,
"click .hide-chapters"
:
"hideChapters"
},
render
:
function
()
{
this
.
$el
.
html
(
this
.
template
(
this
.
model
.
attributes
));
return
this
;
},
editTextbook
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
collection
.
trigger
(
"editOne"
,
this
.
model
);
},
confirmDelete
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
var
textbook
=
this
.
model
,
collection
=
this
.
model
.
collection
;
var
msg
=
new
CMS
.
Models
.
WarningMessage
({
title
:
_
.
str
.
sprintf
(
gettext
(
"Delete “%s”?"
),
textbook
.
escape
(
'name'
)),
message
:
gettext
(
"Deleting a textbook cannot be undone and once deleted any reference to it in your courseware's navigation will also be removed."
),
actions
:
{
primary
:
{
text
:
gettext
(
"Delete"
),
click
:
function
(
view
)
{
view
.
hide
();
collection
.
remove
(
textbook
);
var
delmsg
=
new
CMS
.
Models
.
SystemFeedback
({
intent
:
"saving"
,
title
:
gettext
(
"Deleting…"
)
});
var
notif
=
new
CMS
.
Views
.
Notification
({
model
:
delmsg
,
closeIcon
:
false
,
minShown
:
1250
});
collection
.
save
({
complete
:
function
()
{
notif
.
hide
();
}
});
}
},
secondary
:
[{
text
:
gettext
(
"Cancel"
),
click
:
function
(
view
)
{
view
.
hide
();
}
}]
}
});
var
prompt
=
new
CMS
.
Views
.
Prompt
({
model
:
msg
});
},
showChapters
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
set
(
'showChapters'
,
true
);
},
hideChapters
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
set
(
'showChapters'
,
false
);
}
});
CMS
.
Views
.
TextbookEdit
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#new-textbook-tpl"
).
text
());
var
chapters
=
this
.
model
.
get
(
'chapters'
);
this
.
listenTo
(
chapters
,
"add"
,
this
.
addOne
);
this
.
listenTo
(
chapters
,
"reset"
,
this
.
addAll
);
this
.
listenTo
(
chapters
,
"all"
,
this
.
render
);
this
.
listenTo
(
this
.
model
.
collection
,
"editOne"
,
this
.
remove
);
},
tagName
:
"li"
,
render
:
function
()
{
this
.
$el
.
html
(
this
.
template
({
name
:
this
.
model
.
escape
(
'name'
),
errors
:
null
}));
this
.
addAll
();
return
this
;
},
events
:
{
"change input[name=textbook-name]"
:
"setName"
,
"submit"
:
"setAndClose"
,
"click .action-cancel"
:
"cancel"
,
"click .action-add-chapter"
:
"createChapter"
},
addOne
:
function
(
chapter
)
{
var
view
=
new
CMS
.
Views
.
ChapterEdit
({
model
:
chapter
});
this
.
$
(
"ol.chapters"
).
append
(
view
.
render
().
el
)
return
this
;
},
addAll
:
function
()
{
this
.
model
.
get
(
'chapters'
).
each
(
this
.
addOne
,
this
);
},
createChapter
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
setValues
();
this
.
model
.
get
(
'chapters'
).
add
([{}]);
},
setName
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
set
(
"name"
,
this
.
$
(
"#textbook-name-input"
).
val
(),
{
silent
:
true
});
},
setValues
:
function
()
{
this
.
setName
();
var
that
=
this
;
_
.
each
(
this
.
$
(
"li"
),
function
(
li
,
i
)
{
var
chapter
=
that
.
model
.
get
(
'chapters'
).
at
(
i
);
chapter
.
set
({
"name"
:
$
(
".chapter-name"
,
li
).
val
(),
"asset_path"
:
$
(
".chapter-asset-path"
,
li
).
val
()
})
});
return
this
;
},
setAndClose
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
setValues
();
msg
=
new
CMS
.
Models
.
SystemFeedback
({
intent
:
"saving"
,
title
:
gettext
(
"Saving…"
)
});
notif
=
new
CMS
.
Views
.
Notification
({
model
:
msg
,
closeIcon
:
false
,
minShown
:
1250
});
var
that
=
this
;
this
.
model
.
collection
.
save
({
success
:
function
()
{
that
.
close
();
},
complete
:
function
()
{
notif
.
hide
();
}
});
},
cancel
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
return
this
.
close
();
},
close
:
function
()
{
var
textbooks
=
this
.
model
.
collection
;
delete
textbooks
.
editing
;
this
.
remove
();
// if the textbook has no content, remove it from the collection
if
(
this
.
model
.
isEmpty
())
{
textbooks
.
remove
(
this
.
model
);
}
textbooks
.
trigger
(
'render'
);
return
this
;
}
});
CMS
.
Views
.
ListTextbooks
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
emptyTemplate
=
_
.
template
(
$
(
"#no-textbooks-tpl"
).
text
());
this
.
listenTo
(
this
.
collection
,
'all'
,
this
.
render
);
},
tagName
:
"ul"
,
className
:
"textbooks"
,
render
:
function
()
{
var
textbooks
=
this
.
collection
;
if
(
textbooks
.
length
===
0
)
{
this
.
$el
.
html
(
this
.
emptyTemplate
());
}
else
{
var
$el
=
this
.
$el
;
$el
.
empty
();
textbooks
.
each
(
function
(
textbook
)
{
var
view
;
if
(
textbook
===
textbooks
.
editing
)
{
view
=
new
CMS
.
Views
.
TextbookEdit
({
model
:
textbook
});
}
else
{
view
=
new
CMS
.
Views
.
TextbookShow
({
model
:
textbook
});
}
$el
.
append
(
view
.
render
().
el
);
});
}
return
this
;
},
events
:
{
"click .new-button"
:
"addOne"
},
addOne
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
// if the existing edited textbook is empty, don't do anything
if
(
this
.
collection
.
editing
&&
this
.
collection
.
editing
.
isEmpty
())
{
return
;
}
var
m
=
new
this
.
collection
.
model
();
this
.
collection
.
add
(
m
);
this
.
collection
.
trigger
(
"editOne"
,
m
);
}
});
CMS
.
Views
.
ChapterEdit
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#new-chapter-tpl"
).
text
());
this
.
listenTo
(
this
.
model
,
"change"
,
this
.
render
);
},
tagName
:
"li"
,
className
:
function
()
{
return
"field-group chapter chapter"
+
this
.
model
.
get
(
'order'
);
},
render
:
function
()
{
this
.
$el
.
html
(
this
.
template
({
name
:
this
.
model
.
escape
(
'name'
),
asset_path
:
this
.
model
.
escape
(
'asset_path'
),
order
:
this
.
model
.
get
(
'order'
)
}));
return
this
;
},
events
:
{
"click .action-close"
:
"removeChapter"
,
"click .action-upload"
:
"openUploadDialog"
,
"submit"
:
"uploadAsset"
},
removeChapter
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
collection
.
remove
(
this
.
model
);
return
this
.
remove
();
},
openUploadDialog
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
var
msg
=
new
CMS
.
Models
.
FileUpload
({
title
:
_
.
str
.
sprintf
(
gettext
(
"Upload a new asset to %s"
),
section
.
escape
(
'name'
)),
message
:
"This is sample text about asset upload requirements, like no bigger than 2MB, must be in PDF format or whatever."
});
var
view
=
new
CMS
.
Views
.
UploadDialog
({
model
:
msg
,
chapter
:
this
.
model
});
$
(
".wrapper-view"
).
after
(
view
.
show
().
el
);
}
});
CMS
.
Views
.
UploadDialog
=
Backbone
.
View
.
extend
({
options
:
{
shown
:
true
},
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#upload-dialog-tpl"
).
text
());
this
.
listenTo
(
this
.
model
,
"change"
,
this
.
render
);
},
render
:
function
()
{
// some browsers (like Chrome) allow you to assign to the .files attribute
// of an <input type="file"> DOM element -- for those browsers, we can
// create a new DOM element and assign the old content to it. Other browsers
// (like Firefox) make this attribute read-only, and we have to save the
// old DOM element in order to save it's content. For compatibility purposes,
// we'll just save the old element every time.
var
oldInput
=
this
.
$
(
"input[type=file]"
).
get
(
0
),
selectedFile
;
if
(
oldInput
&&
oldInput
.
files
.
length
)
{
selectedFile
=
oldInput
.
files
[
0
];
}
this
.
$el
.
html
(
this
.
template
({
shown
:
this
.
options
.
shown
,
url
:
UPLOAD_ASSET_CALLBACK_URL
,
title
:
this
.
model
.
escape
(
'title'
),
message
:
this
.
model
.
escape
(
'message'
),
selectedFile
:
selectedFile
,
uploading
:
this
.
model
.
get
(
'uploading'
),
uploadedBytes
:
this
.
model
.
get
(
'uploadedBytes'
),
totalBytes
:
this
.
model
.
get
(
'totalBytes'
)
}));
if
(
oldInput
)
{
this
.
$
(
'input[type=file]'
).
replaceWith
(
oldInput
);
}
return
this
;
},
events
:
{
"change input[type=file]"
:
"selectFile"
,
"click .action-cancel"
:
"hideAndRemove"
,
"click .action-upload"
:
"upload"
},
selectFile
:
function
(
e
)
{
this
.
model
.
set
(
'fileList'
,
e
.
target
.
files
);
},
show
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
options
.
shown
=
true
;
$body
.
addClass
(
'dialog-is-shown'
);
return
this
.
render
();
},
hide
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
options
.
shown
=
false
;
$body
.
removeClass
(
'dialog-is-shown'
);
return
this
.
render
();
},
hideAndRemove
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
return
this
.
hide
().
remove
();
},
upload
:
function
(
e
)
{
this
.
model
.
set
(
'uploading'
,
true
);
this
.
$
(
"form"
).
ajaxSubmit
({
success
:
_
.
bind
(
this
.
success
,
this
),
error
:
_
.
bind
(
this
.
error
,
this
),
uploadProgress
:
_
.
bind
(
this
.
progress
,
this
),
data
:
{
notifyOnError
:
false
}
});
},
progress
:
function
(
event
,
position
,
total
,
percentComplete
)
{
this
.
model
.
set
({
"uploadedBytes"
:
position
,
"totalBytes"
:
total
});
},
success
:
function
(
response
,
statusText
,
xhr
,
form
)
{
this
.
model
.
set
(
'uploading'
,
false
);
var
chapter
=
this
.
options
.
chapter
;
if
(
chapter
)
{
var
options
=
{};
if
(
!
chapter
.
get
(
"name"
))
{
options
.
name
=
response
.
displayname
;
}
options
.
asset_path
=
response
.
url
;
chapter
.
set
(
options
);
}
this
.
remove
();
},
error
:
function
()
{
this
.
model
.
set
({
"uploading"
:
false
,
"uploadedBytes"
:
0
,
"title"
:
gettext
(
"We're sorry, there was an error"
)
});
}
});
cms/templates/textbooks.html
View file @
9af447de
...
...
@@ -25,444 +25,12 @@
<
%
block
name=
"jsextra"
>
<script
type=
"text/javascript"
src=
"${static.url('js/vendor/backbone-associations-min.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/models/textbooks.js')}"
></script>
<script
type=
"text/javascript"
src=
"${static.url('js/views/textbooks.js')}"
></script>
<script
type=
"text/javascript"
>
window
.
UPLOAD_ASSET_CALLBACK_URL
=
"${upload_asset_callback_url}"
window
.
TEXTBOOK_URL
=
"${textbook_url}"
CMS
.
Models
.
Textbook
=
Backbone
.
AssociatedModel
.
extend
({
defaults
:
function
()
{
return
{
name
:
""
,
chapters
:
new
CMS
.
Collections
.
ChapterSet
([{}]),
showChapters
:
false
};
},
relations
:
[{
type
:
Backbone
.
Many
,
key
:
"chapters"
,
relatedModel
:
"CMS.Models.Chapter"
,
collectionType
:
"CMS.Collections.ChapterSet"
}],
isEmpty
:
function
()
{
return
!
this
.
get
(
'name'
)
&&
this
.
get
(
'chapters'
).
isEmpty
();
},
parse
:
function
(
response
)
{
if
(
"tab_title"
in
response
&&
!
(
"name"
in
response
))
{
response
.
name
=
response
.
tab_title
;
delete
response
.
tab_title
;
}
if
(
"url"
in
response
&&
!
(
"chapters"
in
response
))
{
response
.
chapters
=
{
"url"
:
response
.
url
};
delete
response
.
url
;
}
_
.
each
(
response
.
chapters
,
function
(
chapter
,
i
)
{
chapter
.
order
=
chapter
.
order
||
i
+
1
;
})
return
response
;
},
toJSON
:
function
()
{
return
{
tab_title
:
this
.
get
(
'name'
),
chapters
:
this
.
get
(
'chapters'
).
toJSON
()
}
}
})
CMS
.
Views
.
TextbookShow
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#show-textbook-tpl"
).
text
());
this
.
listenTo
(
this
.
model
,
"change"
,
this
.
render
);
},
tagName
:
"li"
,
events
:
{
"click .edit"
:
"editTextbook"
,
"click .delete"
:
"confirmDelete"
,
"click .show-chapters"
:
"showChapters"
,
"click .hide-chapters"
:
"hideChapters"
},
render
:
function
()
{
this
.
$el
.
html
(
this
.
template
(
this
.
model
.
attributes
));
return
this
;
},
editTextbook
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
collection
.
trigger
(
"editOne"
,
this
.
model
);
},
confirmDelete
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
var
textbook
=
this
.
model
,
collection
=
this
.
model
.
collection
;
var
msg
=
new
CMS
.
Models
.
WarningMessage
({
title
:
_
.
str
.
sprintf
(
gettext
(
"Delete “%s”?"
),
textbook
.
escape
(
'name'
)),
message
:
gettext
(
"Deleting a textbook cannot be undone and once deleted any reference to it in your courseware's navigation will also be removed."
),
actions
:
{
primary
:
{
text
:
gettext
(
"Delete"
),
click
:
function
(
view
)
{
view
.
hide
();
collection
.
remove
(
textbook
);
var
delmsg
=
new
CMS
.
Models
.
SystemFeedback
({
intent
:
"saving"
,
title
:
gettext
(
"Deleting…"
)
});
var
notif
=
new
CMS
.
Views
.
Notification
({
model
:
delmsg
,
closeIcon
:
false
,
minShown
:
1250
});
collection
.
save
({
complete
:
function
()
{
notif
.
hide
();
}
});
}
},
secondary
:
[{
text
:
gettext
(
"Cancel"
),
click
:
function
(
view
)
{
view
.
hide
();
}
}]
}
});
var
prompt
=
new
CMS
.
Views
.
Prompt
({
model
:
msg
});
},
showChapters
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
set
(
'showChapters'
,
true
);
},
hideChapters
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
set
(
'showChapters'
,
false
);
}
})
CMS
.
Views
.
TextbookEdit
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#new-textbook-tpl"
).
text
());
var
chapters
=
this
.
model
.
get
(
'chapters'
);
this
.
listenTo
(
chapters
,
"add"
,
this
.
addOne
);
this
.
listenTo
(
chapters
,
"reset"
,
this
.
addAll
);
this
.
listenTo
(
chapters
,
"all"
,
this
.
render
);
this
.
listenTo
(
this
.
model
.
collection
,
"editOne"
,
this
.
remove
);
},
tagName
:
"li"
,
render
:
function
()
{
this
.
$el
.
html
(
this
.
template
({
name
:
this
.
model
.
escape
(
'name'
),
errors
:
null
}));
this
.
addAll
();
return
this
;
},
events
:
{
"change input[name=textbook-name]"
:
"setName"
,
"submit"
:
"setAndClose"
,
"click .action-cancel"
:
"cancel"
,
"click .action-add-chapter"
:
"createChapter"
},
addOne
:
function
(
chapter
)
{
var
view
=
new
CMS
.
Views
.
ChapterEdit
({
model
:
chapter
});
this
.
$
(
"ol.chapters"
).
append
(
view
.
render
().
el
)
return
this
;
},
addAll
:
function
()
{
this
.
model
.
get
(
'chapters'
).
each
(
this
.
addOne
,
this
);
},
createChapter
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
setValues
();
this
.
model
.
get
(
'chapters'
).
add
([{}]);
},
setName
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
set
(
"name"
,
this
.
$
(
"#textbook-name-input"
).
val
(),
{
silent
:
true
});
},
setValues
:
function
()
{
this
.
setName
();
var
that
=
this
;
_
.
each
(
this
.
$
(
"li"
),
function
(
li
,
i
)
{
var
chapter
=
that
.
model
.
get
(
'chapters'
).
at
(
i
);
chapter
.
set
({
"name"
:
$
(
".chapter-name"
,
li
).
val
(),
"asset_path"
:
$
(
".chapter-asset-path"
,
li
).
val
()
})
});
return
this
;
},
setAndClose
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
setValues
();
msg
=
new
CMS
.
Models
.
SystemFeedback
({
intent
:
"saving"
,
title
:
gettext
(
"Saving…"
)
});
notif
=
new
CMS
.
Views
.
Notification
({
model
:
msg
,
closeIcon
:
false
,
minShown
:
1250
});
var
that
=
this
;
this
.
model
.
collection
.
save
({
success
:
function
()
{
that
.
close
();
},
complete
:
function
()
{
notif
.
hide
();
}
})
},
cancel
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
return
this
.
close
();
},
close
:
function
()
{
var
textbooks
=
this
.
model
.
collection
;
delete
textbooks
.
editing
;
this
.
remove
();
// if the textbook has no content, remove it from the collection
if
(
this
.
model
.
isEmpty
())
{
textbooks
.
remove
(
this
.
model
);
}
textbooks
.
trigger
(
'render'
);
return
this
;
}
})
CMS
.
Collections
.
TextbookSet
=
Backbone
.
Collection
.
extend
({
model
:
CMS
.
Models
.
Textbook
,
url
:
TEXTBOOK_URL
,
initialize
:
function
()
{
this
.
listenTo
(
this
,
"editOne"
,
this
.
editOne
);
},
editOne
:
function
(
textbook
)
{
this
.
editing
=
textbook
;
},
save
:
function
(
options
)
{
return
this
.
sync
(
'update'
,
this
,
options
);
}
})
CMS
.
Views
.
ListTextbooks
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
emptyTemplate
=
_
.
template
(
$
(
"#no-textbooks-tpl"
).
text
());
this
.
listenTo
(
this
.
collection
,
'all'
,
this
.
render
);
},
tagName
:
"ul"
,
className
:
"textbooks"
,
render
:
function
()
{
var
textbooks
=
this
.
collection
;
if
(
textbooks
.
length
===
0
)
{
this
.
$el
.
html
(
this
.
emptyTemplate
());
}
else
{
var
$el
=
this
.
$el
;
$el
.
empty
();
textbooks
.
each
(
function
(
textbook
)
{
var
view
;
if
(
textbook
===
textbooks
.
editing
)
{
view
=
new
CMS
.
Views
.
TextbookEdit
({
model
:
textbook
});
}
else
{
view
=
new
CMS
.
Views
.
TextbookShow
({
model
:
textbook
});
}
$el
.
append
(
view
.
render
().
el
);
})
}
return
this
;
},
events
:
{
"click .new-button"
:
"addOne"
},
addOne
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
// if the existing edited textbook is empty, don't do anything
if
(
this
.
collection
.
editing
&&
this
.
collection
.
editing
.
isEmpty
())
{
return
;
}
var
m
=
new
this
.
collection
.
model
;
this
.
collection
.
add
(
m
);
this
.
collection
.
trigger
(
"editOne"
,
m
);
}
})
CMS
.
Models
.
Chapter
=
Backbone
.
AssociatedModel
.
extend
({
defaults
:
function
()
{
return
{
name
:
""
,
asset_path
:
""
,
order
:
this
.
collection
?
this
.
collection
.
nextOrder
()
:
1
}
},
isEmpty
:
function
()
{
return
!
this
.
get
(
'name'
)
&&
!
this
.
get
(
'asset_path'
);
},
parse
:
function
(
response
)
{
if
(
"title"
in
response
&&
!
(
"name"
in
response
))
{
response
.
name
=
response
.
title
;
delete
response
.
title
;
}
if
(
"url"
in
response
&&
!
(
"asset_path"
in
response
))
{
response
.
asset_path
=
response
.
url
;
delete
response
.
url
;
}
return
response
;
},
toJSON
:
function
()
{
return
{
title
:
this
.
get
(
'name'
),
url
:
this
.
get
(
'asset_path'
)
}
}
})
CMS
.
Collections
.
ChapterSet
=
Backbone
.
Collection
.
extend
({
model
:
CMS
.
Models
.
Chapter
,
comparator
:
"order"
,
nextOrder
:
function
()
{
if
(
!
this
.
length
)
return
1
;
return
this
.
last
().
get
(
'order'
)
+
1
;
},
isEmpty
:
function
()
{
return
this
.
length
===
0
||
this
.
every
(
function
(
m
)
{
return
m
.
isEmpty
();
});
}
})
CMS
.
Views
.
ChapterEdit
=
Backbone
.
View
.
extend
({
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#new-chapter-tpl"
).
text
());
this
.
listenTo
(
this
.
model
,
"change"
,
this
.
render
);
},
tagName
:
"li"
,
className
:
function
()
{
return
"field-group chapter chapter"
+
this
.
model
.
get
(
'order'
);
},
render
:
function
()
{
this
.
$el
.
html
(
this
.
template
({
name
:
this
.
model
.
escape
(
'name'
),
asset_path
:
this
.
model
.
escape
(
'asset_path'
),
order
:
this
.
model
.
get
(
'order'
)
}));
return
this
;
},
events
:
{
"click .action-close"
:
"removeChapter"
,
"click .action-upload"
:
"openUploadDialog"
,
"submit"
:
"uploadAsset"
},
removeChapter
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
model
.
collection
.
remove
(
this
.
model
);
return
this
.
remove
();
},
openUploadDialog
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
var
msg
=
new
CMS
.
Models
.
FileUpload
({
title
:
_
.
str
.
sprintf
(
gettext
(
"Upload a new asset to %s"
),
section
.
escape
(
'name'
)),
message
:
"This is sample text about asset upload requirements, like no bigger than 2MB, must be in PDF format or whatever."
})
var
view
=
new
CMS
.
Views
.
UploadDialog
({
model
:
msg
,
chapter
:
this
.
model
})
$
(
".wrapper-view"
).
after
(
view
.
show
().
el
)
}
})
CMS
.
Models
.
FileUpload
=
Backbone
.
Model
.
extend
({
defaults
:
{
"title"
:
""
,
"message"
:
""
,
"selectFile"
:
null
,
"uploading"
:
false
,
"uploadedBytes"
:
0
,
"totalBytes"
:
0
,
}
});
CMS
.
Views
.
UploadDialog
=
Backbone
.
View
.
extend
({
options
:
{
shown
:
true
},
initialize
:
function
()
{
this
.
template
=
_
.
template
(
$
(
"#upload-dialog-tpl"
).
text
());
this
.
listenTo
(
this
.
model
,
"change"
,
this
.
render
);
},
render
:
function
()
{
// some browsers (like Chrome) allow you to assign to the .files attribute
// of an
<
input
type
=
"file"
>
DOM
element
--
for
those
browsers
,
we
can
// create a new DOM element and assign the old content to it. Other browsers
// (like Firefox) make this attribute read-only, and we have to save the
// old DOM element in order to save it's content. For compatibility purposes,
// we'll just save the old element every time.
var
oldInput
=
this
.
$
(
"input[type=file]"
).
get
(
0
),
selectedFile
;
if
(
oldInput
&&
oldInput
.
files
.
length
)
{
selectedFile
=
oldInput
.
files
[
0
];
}
this
.
$el
.
html
(
this
.
template
({
shown
:
this
.
options
.
shown
,
url
:
UPLOAD_ASSET_CALLBACK_URL
,
title
:
this
.
model
.
escape
(
'title'
),
message
:
this
.
model
.
escape
(
'message'
),
selectedFile
:
selectedFile
,
uploading
:
this
.
model
.
get
(
'uploading'
),
uploadedBytes
:
this
.
model
.
get
(
'uploadedBytes'
),
totalBytes
:
this
.
model
.
get
(
'totalBytes'
),
}))
if
(
oldInput
)
{
this
.
$
(
'input[type=file]'
).
replaceWith
(
oldInput
);
}
return
this
;
},
events
:
{
"change input[type=file]"
:
"selectFile"
,
"click .action-cancel"
:
"hideAndRemove"
,
"click .action-upload"
:
"upload"
},
selectFile
:
function
(
e
)
{
this
.
model
.
set
(
'fileList'
,
e
.
target
.
files
)
},
show
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
options
.
shown
=
true
;
$body
.
addClass
(
'dialog-is-shown'
);
return
this
.
render
();
},
hide
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
this
.
options
.
shown
=
false
;
$body
.
removeClass
(
'dialog-is-shown'
);
return
this
.
render
();
},
hideAndRemove
:
function
(
e
)
{
if
(
e
&&
e
.
preventDefault
)
{
e
.
preventDefault
();
}
return
this
.
hide
().
remove
();
},
upload
:
function
(
e
)
{
this
.
model
.
set
(
'uploading'
,
true
);
this
.
$
(
"form"
).
ajaxSubmit
({
success
:
_
.
bind
(
this
.
success
,
this
),
error
:
_
.
bind
(
this
.
error
,
this
),
uploadProgress
:
_
.
bind
(
this
.
progress
,
this
),
data
:
{
notifyOnError
:
false
}
});
},
progress
:
function
(
event
,
position
,
total
,
percentComplete
)
{
this
.
model
.
set
({
"uploadedBytes"
:
position
,
"totalBytes"
:
total
,
})
},
success
:
function
(
response
,
statusText
,
xhr
,
form
)
{
this
.
model
.
set
(
'uploading'
,
false
);
var
chapter
=
this
.
options
.
chapter
;
if
(
chapter
)
{
var
options
=
{}
if
(
!
chapter
.
get
(
"name"
))
{
options
.
name
=
response
.
displayname
;
}
options
.
asset_path
=
response
.
url
;
chapter
.
set
(
options
);
}
this
.
remove
();
},
error
:
function
()
{
this
.
model
.
set
({
"uploading"
:
false
,
"uploadedBytes"
:
0
,
"title"
:
gettext
(
"We're sorry, there was an error"
),
});
}
})
var
section
=
new
CMS
.
Models
.
Section
({
window
.
section
=
new
CMS
.
Models
.
Section
({
id
:
"${course.id}"
,
name
:
"${course.display_name_with_default | h}"
});
...
...
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