Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cms/templates/unit.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -31,6 +32,10 @@
});
});
</script>

<script type="text/template" id="image-modal-tpl">
<%static:include path="js/imageModal.underscore" />
</script>

</%block>
<%block name="content">
Expand Down Expand Up @@ -207,5 +212,7 @@ <h4 class="header">${_("Unit Location")}</h4>
</div>
</div>
</div>



</%block>
145 changes: 145 additions & 0 deletions common/lib/xmodule/xmodule/css/html/display.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}
}
4 changes: 4 additions & 0 deletions common/lib/xmodule/xmodule/html_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
109 changes: 109 additions & 0 deletions common/lib/xmodule/xmodule/js/src/html/imageModal.js
Original file line number Diff line number Diff line change
@@ -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;
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment explaining that jQuery (or really, Sizzle) does not support the :hover pseudo-selector, and therefore we need to use this event to detect if the user is hovering over the image modal? I spent a fair amount of time trying to track that down, and I don't want others to have to track it down again.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


// 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"));
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how I feel about some of this duplication. Is there any way to split out this logic to a common function where we just pass in a single jQuery object (this or this.closest('.imageModal'), presumably) and do all of the operations on that object?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


// 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');
}
});
});
6 changes: 6 additions & 0 deletions common/lib/xmodule/xmodule/templates/html/image_modal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
metadata:
display_name: Image Modal
data: |
<h2>Title of Unit (click image to zoom)</h2>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure (click to zoom) are the best instructions here. Perhaps @mhoeber can help you with details, but in general we tend to avoid phrases that imply specific interaction affordances (like "click here"), since they aren't always applicable in given contexts (using a tablet/mobile device or assistive tech are two common examples where "clicking" doesn't hold up).

<a href="http://static.class.stanford.edu/stanford-hills-big.jpg" class="modal-content"><img alt="The Stanford Hills" src="http://static.class.stanford.edu/stanford-hills-small.jpg" /></a>
42 changes: 42 additions & 0 deletions common/templates/js/imageModal.underscore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div class="wrapper-modal wrapper-modal-image">
<section class="image-link">
<%= smallHTML%>
<a href="#" class="modal-ui-icon action-fullscreen" role="button">
<span class="label">
<i class="icon-fullscreen icon-large"></i> <%= gettext("Fullscreen") %>
</span>
</a>
</section>

<section class="image-modal">
<section class="image-content">
<div class="image-wrapper">
<img alt="<%= largeALT %>, <%= gettext('Large') %>" src="<%= largeSRC %>" />
</div>

<a href="#" class="modal-ui-icon action-close" role="button">
<span class="label">
<i class="icon-remove icon-large"></i> <%= gettext("Close") %>
</span>
</a>

<ul class="image-controls">
<li class="image-control">
<a href="#" class="modal-ui-icon action-zoom-in" role="button">
<span class="label">
<i class="icon-zoom-in icon-large"></i> <%= gettext("Zoom In") %>
</span>
</a>
</li>

<li class="image-control">
<a href="#" class="modal-ui-icon action-zoom-out is-disabled" role="button">
<span class="label">
<i class="icon-zoom-out icon-large"></i> <%= gettext("Zoom Out") %>
</span>
</a>
</li>
</ul>
</section>
</section>
</div>
4 changes: 4 additions & 0 deletions lms/templates/courseware/courseware.html
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@
</script>
% endif

<script type="text/template" id="image-modal-tpl">
<%static:include path="js/imageModal.underscore" />
</script>

${fragment.foot_html()}

</%block>
Expand Down