mirror of https://github.com/zulip/zulip.git
hotkeys: Add lightbox image feed with controls.
This adds an image feed that you can scroll through with hotkeys in the lightbox. The left and right arrow keys along with the left and right arrows will go to the prev/next image, and clicking on an image will also take a user to that image.
This commit is contained in:
parent
fa5a093738
commit
2775707a67
|
@ -215,6 +215,7 @@ function stubbing(func_name_to_stub, test_function) {
|
|||
end: 35,
|
||||
home: 36,
|
||||
left_arrow: 37,
|
||||
right_arrow: 39,
|
||||
page_up: 33,
|
||||
page_down: 34,
|
||||
spacebar: 32,
|
||||
|
@ -273,6 +274,10 @@ function stubbing(func_name_to_stub, test_function) {
|
|||
assert_mapping('up_arrow', 'navigate.up');
|
||||
assert_mapping('+', 'reactions.toggle_reaction', true, false);
|
||||
|
||||
hotkey.is_lightbox_open = return_true;
|
||||
assert_mapping('left_arrow', 'lightbox.prev');
|
||||
assert_mapping('right_arrow', 'lightbox.next');
|
||||
|
||||
hotkey.is_settings_page = return_true;
|
||||
assert_unmapped('end');
|
||||
assert_unmapped('home');
|
||||
|
|
|
@ -526,6 +526,48 @@ $(function () {
|
|||
$("#lightbox_overlay .download").click(function () {
|
||||
this.blur();
|
||||
});
|
||||
|
||||
$("#lightbox_overlay").on("click", ".image-list .image", function () {
|
||||
var $image_list = $(this).parent();
|
||||
|
||||
var image = new Image();
|
||||
image.src = this.dataset.src;
|
||||
image.title = this.title;
|
||||
|
||||
lightbox.open({
|
||||
type: "photo",
|
||||
user: message_store.get($(this).attr("data-zid")).sender_full_name,
|
||||
image: image,
|
||||
});
|
||||
|
||||
$(".image-list .image.selected").removeClass("selected");
|
||||
$(this).addClass("selected");
|
||||
|
||||
var parentOffset = this.parentNode.clientWidth + this.parentNode.scrollLeft;
|
||||
// this is the left and right of the image compared to its parent.
|
||||
var coords = {
|
||||
left: this.offsetLeft,
|
||||
right: this.offsetLeft + this.clientWidth,
|
||||
};
|
||||
|
||||
if (coords.right > parentOffset) {
|
||||
// add 2px margin
|
||||
$image_list.animate({
|
||||
scrollLeft: coords.right - this.parentNode.clientWidth + 2,
|
||||
}, 100);
|
||||
} else if (coords.left < this.parentNode.scrollLeft) {
|
||||
// subtract 2px margin
|
||||
$image_list.animate({ scrollLeft: coords.left - 2 }, 100);
|
||||
}
|
||||
});
|
||||
|
||||
$("#lightbox_overlay").on("click", ".center .arrow", function () {
|
||||
var direction = $(this).attr("data-direction");
|
||||
|
||||
if (/^(next|prev)$/.test(direction)) {
|
||||
lightbox[direction]();
|
||||
}
|
||||
});
|
||||
}());
|
||||
|
||||
// MAIN CLICK HANDLER
|
||||
|
|
|
@ -29,6 +29,10 @@ exports.is_settings_page = function () {
|
|||
return (/^#*(settings|administration)/g).test(window.location.hash);
|
||||
};
|
||||
|
||||
exports.is_lightbox_open = function () {
|
||||
return lightbox.is_open;
|
||||
};
|
||||
|
||||
var actions_dropdown_hotkeys = [
|
||||
'down_arrow',
|
||||
'up_arrow',
|
||||
|
@ -57,7 +61,8 @@ var keydown_unshift_mappings = {
|
|||
34: {name: 'page_down', message_view_only: true}, // page down
|
||||
35: {name: 'end', message_view_only: true}, // end
|
||||
36: {name: 'home', message_view_only: true}, // home
|
||||
37: {name: 'left_arrow', message_view_only: true}, // left arrow
|
||||
37: {name: 'left_arrow', message_view_only: false}, // left arrow
|
||||
39: {name: 'right_arrow', message_view_only: false}, // right arrow
|
||||
38: {name: 'up_arrow', message_view_only: true}, // up arrow
|
||||
40: {name: 'down_arrow', message_view_only: true}, // down arrow
|
||||
};
|
||||
|
@ -183,7 +188,7 @@ exports.process_escape_key = function (e) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if ($("#lightbox_overlay").hasClass("show")) {
|
||||
if (exports.is_lightbox_open()) {
|
||||
modals.close_modal("lightbox");
|
||||
return true;
|
||||
}
|
||||
|
@ -506,10 +511,22 @@ exports.process_hotkey = function (e, hotkey) {
|
|||
}
|
||||
|
||||
if (event_name === 'left_arrow') {
|
||||
if (exports.is_lightbox_open()) {
|
||||
lightbox.prev();
|
||||
return true;
|
||||
}
|
||||
|
||||
message_edit.edit_last_sent_message();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event_name === 'right_arrow') {
|
||||
if (exports.is_lightbox_open()) {
|
||||
lightbox.next();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Shortcuts that don't require a message
|
||||
switch (event_name) {
|
||||
case 'compose': // 'c': compose
|
||||
|
|
|
@ -1,10 +1,40 @@
|
|||
var lightbox = (function () {
|
||||
var exports = {};
|
||||
|
||||
var images = [];
|
||||
var is_open = false;
|
||||
|
||||
var get_image_title = function (image) {
|
||||
var image_title = $(image).attr("title");
|
||||
if (image_title) {
|
||||
return image_title;
|
||||
}
|
||||
return $(image).parent().attr("title");
|
||||
};
|
||||
|
||||
function display_image(image, user) {
|
||||
if (!is_open) {
|
||||
images = Array.prototype.slice.call($(".focused_table .messagebox-content img"));
|
||||
var $image_list = $("#lightbox_overlay .image-list").html("");
|
||||
|
||||
images.forEach(function (img) {
|
||||
var src = img.getAttribute("src");
|
||||
var className = $(image).attr("src").match(src) ? "image selected" : "image";
|
||||
|
||||
var node = $("<div></div>", {
|
||||
class: className,
|
||||
title: get_image_title(img),
|
||||
"data-zid": $(img).closest(".message_row").attr("zid"),
|
||||
"data-src": src,
|
||||
}).css({ backgroundImage: "url(" + src + ")"});
|
||||
|
||||
$image_list.append(node);
|
||||
}, "");
|
||||
}
|
||||
|
||||
// image should be an Image Object in JavaScript.
|
||||
var url = $(image).attr("src");
|
||||
var title = $(image).parent().attr("title");
|
||||
var title = get_image_title(image);
|
||||
|
||||
$("#lightbox_overlay .player-container").hide();
|
||||
$("#lightbox_overlay .image-actions, .image-description, .download").show();
|
||||
|
@ -38,9 +68,11 @@ exports.open = function (data) {
|
|||
switch (data.type) {
|
||||
case "photo":
|
||||
display_image(data.image, data.user);
|
||||
is_open = true;
|
||||
break;
|
||||
case "youtube":
|
||||
display_youtube_video(data.id);
|
||||
is_open = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -48,6 +80,7 @@ exports.open = function (data) {
|
|||
|
||||
$("#lightbox_overlay").addClass("show");
|
||||
popovers.hide_all();
|
||||
lightbox.is_open = true;
|
||||
};
|
||||
|
||||
exports.show_from_selected_message = function () {
|
||||
|
@ -74,6 +107,25 @@ exports.show_from_inline_image = function ($img) {
|
|||
}
|
||||
};
|
||||
|
||||
exports.prev = function () {
|
||||
$(".image-list .image.selected").prev().click();
|
||||
};
|
||||
|
||||
exports.next = function () {
|
||||
$(".image-list .image.selected").next().click();
|
||||
};
|
||||
|
||||
Object.defineProperty(exports, "is_open", {
|
||||
get: function () {
|
||||
return is_open;
|
||||
},
|
||||
set: function (value) {
|
||||
if (typeof value === "boolean") {
|
||||
is_open = value;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return exports;
|
||||
}());
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ var modals = (function () {
|
|||
|
||||
lightbox: function () {
|
||||
$(".player-container iframe").remove();
|
||||
lightbox.is_open = false;
|
||||
document.activeElement.blur();
|
||||
},
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
justify-content: center;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: calc(100% - 65px - 30px);
|
||||
height: calc(100% - 65px - 90px);
|
||||
margin: 0px;
|
||||
|
||||
background-size: contain;
|
||||
|
@ -157,6 +157,58 @@
|
|||
white-space: pre;
|
||||
}
|
||||
|
||||
#lightbox_overlay .center .arrow {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin-top: 25px;
|
||||
padding: 5px 10px;
|
||||
|
||||
color: #fff;
|
||||
font-size: 1.8em;
|
||||
font-weight: 100;
|
||||
|
||||
transform: scaleY(2);
|
||||
cursor: pointer;
|
||||
|
||||
opacity: 0.5;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#lightbox_overlay .center .arrow:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
#lightbox_overlay .center .image-list {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
padding: 15px 0px 12px 0px;
|
||||
height: 50px;
|
||||
font-size: 0px;
|
||||
|
||||
max-width: 40vw;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#lightbox_overlay .center .image-list .image {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: 0px 2px;
|
||||
|
||||
background-color: rgba(240, 240, 240, 0.2);
|
||||
opacity: 0.5;
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#lightbox_overlay .image-list .image.selected {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.image-actions .button {
|
||||
font-size: 0.8rem;
|
||||
min-width: inherit;
|
||||
|
@ -199,4 +251,8 @@
|
|||
#lightbox_overlay .image-description .title {
|
||||
max-width: calc(100% - 60px);
|
||||
}
|
||||
|
||||
#lightbox_overlay .center .image-list {
|
||||
max-width: 80vw;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,14 @@ a {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
.no-select {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
p.n-margin {
|
||||
margin: 10px 0px 0px 0px;
|
||||
}
|
||||
|
|
|
@ -18,4 +18,9 @@
|
|||
|
||||
<div class="image-preview overlay-content"></div>
|
||||
<div class="player-container"></div>
|
||||
<div class="center">
|
||||
<div class="arrow no-select" data-direction="prev"><</div>
|
||||
<div class="image-list"></div>
|
||||
<div class="arrow no-select" data-direction="next">></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue