diff --git a/cms/templates/unit.html b/cms/templates/unit.html
index 04d73d8efd94..40aaee6b2c32 100644
--- a/cms/templates/unit.html
+++ b/cms/templates/unit.html
@@ -4,6 +4,7 @@
from django.utils.translation import ugettext as _
from xmodule.modulestore.django import loc_mapper
%>
+<%namespace name='static' file='static_content.html'/>
<%namespace name="units" file="widgets/units.html" />
<%block name="title">${_("Individual Unit")}%block>
<%block name="bodyclass">is-signedin course unit view-unit%block>
@@ -31,6 +32,10 @@
});
});
+
+
%block>
<%block name="content">
@@ -207,5 +212,7 @@
+
+
%block>
diff --git a/common/lib/xmodule/xmodule/css/html/display.scss b/common/lib/xmodule/xmodule/css/html/display.scss
index a4e5bd6ac0e1..6ce6ca5ee902 100644
--- a/common/lib/xmodule/xmodule/css/html/display.scss
+++ b/common/lib/xmodule/xmodule/css/html/display.scss
@@ -145,3 +145,148 @@ th {
background: #eee;
font-weight: bold;
}
+
+
+// image modal
+// --------------------
+
+// modal - image zoom, fill window
+.wrapper-modal-image {
+
+ .modal-ui-icon {
+ position: absolute;
+ display: block;
+ padding: 5px 7px;
+ cursor: pointer;
+ border-radius: 5px;
+ opacity: .9;
+ background: $white;
+ color: $black;
+ border: 2px solid $black;
+
+ .label {
+ font-weight: bold;
+ }
+
+ i {
+ font-style: normal;
+ }
+ }
+
+ .image-link {
+ position: relative;
+ display: block;
+ cursor: pointer;
+
+ .action-fullscreen {
+ display: none;
+ top: 10px;
+ left: 10px;
+ }
+
+ &:hover .action-fullscreen {
+ display: block;
+ }
+ }
+
+ .image-modal {
+ position: fixed;
+ top: 0;
+ left: 0;
+ display: none;
+ height: 100%;
+ width: 100%;
+ @extend %ui-depth5;
+ cursor: pointer;
+ background-color: rgba(0, 0, 0, 0.7);
+
+ .image-content {
+ position: relative;
+ top: 2.5%;
+ display: block;
+ height: 95%;
+ width: 95%;
+ margin: auto;
+ overflow: hidden;
+
+ .image-wrapper {
+ position: relative;
+
+ img {
+ position: relative;
+ display: block;
+ max-width: 100%;
+ max-height: 100%;
+ margin: auto;
+ cursor: default;
+ }
+ }
+
+ .action-close {
+ top: 10px;
+ right: 10px;
+ }
+
+ .image-controls {
+ position: absolute;
+ right: 10px;
+ bottom: 10px;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+
+ .image-control {
+ position: relative;
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+
+ .modal-ui-icon {
+ position: relative;
+
+ &.action-zoom-in {
+ margin-right: 5px;
+ }
+ &.action-zoom-out {
+ margin-left: 5px;
+ }
+ &.is-disabled {
+ opacity: .5;
+ cursor: default;
+ }
+ }
+ }
+ }
+ }
+
+ &.image-is-fit-to-screen {
+ display: block;
+
+ // !important used here to override jQuery.
+ .image-content .image-wrapper {
+ top: 0 !important;
+ left: 0 !important;
+ width: auto !important;
+ height: auto !important;
+
+ img {
+ top: 0 !important;
+ left: 0 !important;
+ }
+ }
+ }
+ &.image-is-zoomed {
+ display: block;
+
+ .image-content .image-wrapper {
+
+ img {
+ max-width: none;
+ max-height: none;
+ margin: 0;
+ cursor: move;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/common/lib/xmodule/xmodule/html_module.py b/common/lib/xmodule/xmodule/html_module.py
index 03c3ed337291..d00effc7db52 100644
--- a/common/lib/xmodule/xmodule/html_module.py
+++ b/common/lib/xmodule/xmodule/html_module.py
@@ -44,6 +44,10 @@ class HtmlModule(HtmlFields, XModule):
resource_string(__name__, 'js/src/javascript_loader.coffee'),
resource_string(__name__, 'js/src/collapsible.coffee'),
resource_string(__name__, 'js/src/html/display.coffee')
+ ],
+ 'js': [
+ resource_string(__name__, 'js/src/html/imageModal.js'),
+ resource_string(__name__, 'js/common_static/js/vendor/draggabilly.pkgd.js')
]
}
js_module_name = "HTMLModule"
diff --git a/common/lib/xmodule/xmodule/js/src/html/imageModal.js b/common/lib/xmodule/xmodule/js/src/html/imageModal.js
new file mode 100644
index 000000000000..19953eae0344
--- /dev/null
+++ b/common/lib/xmodule/xmodule/js/src/html/imageModal.js
@@ -0,0 +1,109 @@
+$(function() {
+
+ // Set up on page load
+ $("a.modal-content").each(function() {
+ var smallImageObject = $(this).children();
+ var largeImageSRC = $(this).attr('href');
+
+ // if contents of zoomable link is image and large image link exists: setup modal
+ if (smallImageObject.is('img') && largeImageSRC) {
+ var data = {
+ "smallHTML": $(this).html(),
+ "largeALT": smallImageObject.attr('alt'),
+ "largeSRC": largeImageSRC
+ };
+ var html = _.template($("#image-modal-tpl").text(), data);
+ $(this).replaceWith(html);
+ }
+ });
+ $('.wrapper-modal-image .image-wrapper img').each(function() {
+ var draggie = new Draggabilly(this, {containment: true});
+ draggie.disable();
+ $(this).closest('.image-modal').data("draggie", draggie);
+ });
+
+ // Opening and closing image modal on clicks
+ $(".wrapper-modal-image .image-link").click(function() {
+ $(this).siblings(".image-modal").addClass('image-is-fit-to-screen');
+ $('body').css('overflow', 'hidden');
+ });
+
+ // variable to detect when modal is being "hovered".
+ // Done this way as jquery doesn't support the :hover psudo-selector as expected.
+ var imageModalImageHover = false;
+ $(".wrapper-modal-image .image-content img, .wrapper-modal-image .image-content .image-controls").hover(function() {
+ imageModalImageHover = true;
+ }, function() {
+ imageModalImageHover = false;
+ });
+
+ // prevent image control button links from scrolling
+ $(".modal-ui-icon").click(function(event) {
+ event.preventDefault();
+ });
+
+ //Define function to close modal
+ function closeModal(imageModal) {
+ imageModal.removeClass('image-is-fit-to-screen').removeClass('image-is-zoomed');
+ $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon.action-zoom-in").removeClass('is-disabled');
+ $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon.action-zoom-out").addClass('is-disabled');
+ var currentDraggie = imageModal.data("draggie");
+ currentDraggie.disable();
+ $('body').css('overflow', 'auto');
+ }
+
+ // Click outside of modal to close it.
+ $(".wrapper-modal-image .image-modal").click(function() {
+ if (!imageModalImageHover){
+ closeModal($(this));
+ }
+ });
+
+ // Click close icon to close modal.
+ $(".wrapper-modal-image .image-content .action-remove").click(function() {
+ closeModal($(this).closest(".image-modal"));
+ });
+
+ // zooming image in modal and allow it to be dragged
+ // Make sure it always starts zero position for below calcs to work
+ $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon").click(function() {
+ if (!$(this).hasClass('is-disabled')) {
+ var mask = $(this).closest(".image-content");
+
+ var imageModal = $(this).closest(".image-modal");
+ var img = imageModal.find("img");
+ var currentDraggie = imageModal.data("draggie");
+
+ if ($(this).hasClass('action-zoom-in')) {
+ imageModal.removeClass('image-is-fit-to-screen').addClass('image-is-zoomed');
+
+ var imgWidth = img.width();
+ var imgHeight = img.height();
+
+ var imgContainerOffsetLeft = imgWidth - mask.width();
+ var imgContainerOffsetTop = imgHeight - mask.height();
+ var imgContainerWidth = imgWidth + imgContainerOffsetLeft;
+ var imgContainerHeight = imgHeight + imgContainerOffsetTop;
+
+ // Set the width and height of the image's container so that the dimensions are equal to the image dimensions + view area dimensions to limit dragging
+ // Set image container top and left to center image at load.
+ img.parent().css({
+ left: -imgContainerOffsetLeft,
+ top: -imgContainerOffsetTop,
+ width: imgContainerWidth,
+ height: imgContainerHeight
+ });
+ img.css({top: imgContainerOffsetTop / 2, left: imgContainerOffsetLeft / 2});
+
+ currentDraggie.enable();
+
+ } else if ($(this).hasClass('action-zoom-out')) {
+ imageModal.removeClass('image-is-zoomed').addClass('image-is-fit-to-screen');
+
+ currentDraggie.disable();
+ }
+
+ $(".wrapper-modal-image .image-content .image-controls .modal-ui-icon").toggleClass('is-disabled');
+ }
+ });
+});
\ No newline at end of file
diff --git a/common/lib/xmodule/xmodule/templates/html/image_modal.yaml b/common/lib/xmodule/xmodule/templates/html/image_modal.yaml
new file mode 100644
index 000000000000..73c4419f66c3
--- /dev/null
+++ b/common/lib/xmodule/xmodule/templates/html/image_modal.yaml
@@ -0,0 +1,6 @@
+---
+metadata:
+ display_name: Image Modal
+data: |
+ Title of Unit (click image to zoom)
+
\ No newline at end of file
diff --git a/common/templates/js/imageModal.underscore b/common/templates/js/imageModal.underscore
new file mode 100644
index 000000000000..40f743228082
--- /dev/null
+++ b/common/templates/js/imageModal.underscore
@@ -0,0 +1,42 @@
+
\ No newline at end of file
diff --git a/lms/templates/courseware/courseware.html b/lms/templates/courseware/courseware.html
index 070c751d1a4e..d1ce55a50b3f 100644
--- a/lms/templates/courseware/courseware.html
+++ b/lms/templates/courseware/courseware.html
@@ -167,6 +167,10 @@
% endif
+
+
${fragment.foot_html()}
%block>