Porównaj commity

...

3 Commity

Autor SHA1 Wiadomość Data
Aonrud 59368171d7 feat: update ILA UI Elements to use new blur feature on sensitive attachments 2023-01-27 18:53:04 +00:00
Aonrud c3024a3cd2 fix: prevent attachment image upscaling 2023-01-27 12:12:42 +00:00
Aonrud 7f4f69bd1a feat: update to new ILA UI Elements version 2023-01-27 10:29:55 +00:00
6 zmienionych plików z 255 dodań i 12 usunięć

Wyświetl plik

@ -268,7 +268,7 @@ nav.flexbox {
align-content: center;
}
img {
width: 100%;
max-width: 100%;
object-fit: cover;
}
}

Wyświetl plik

@ -1,5 +1,5 @@
/*! ILA UI Elements
*Copyright (C) 2021-2022 Aonghus Storey
*Copyright (C) 20212023 Aonghus Storey
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -67,6 +67,96 @@ function makeButton(name, css = "", text = "", title = "", icon = "", handler =
return el;
}
/**
* Adds custom swipe events to a given element.
*
* When instantiated, a `swiped-[DIRECTION]` event will be dispatched when that element is swiped.
* A `swiped` event is also dispatched with the direction in the customEvent.detail, to allow for a single listener if needed.
*
* @public
* @param {HTMLElement} el The element on which to listen for swipe events.
* @fires Swipe#swiped
* @fires Swipe#swiped-up
* @fires Swipe#swiped-down
* @fires Swipe#swiped-left
* @fires Swipe#swiped-right
*/
class Swipe {
constructor(el) {
this._el = el;
el.addEventListener('touchstart',
e => {
this.startX = e.changedTouches[0].clientX;
this.startY = e.changedTouches[0].clientY;
});
el.addEventListener('touchend',
e => {
this.endX = e.changedTouches[0].clientX;
this.endY = e.changedTouches[0].clientY;
this._sendEvents();
});
}
/**
* Event dispatched by any swipe.
* @public
* @event Swipe#swiped
* @type {object}
* @property {object} detail
* @property {string} detail.direction - The direction of the swipe action.
*/
/**
* Event dispatched on swipe up.
* @public
* @event Swipe#swiped-up
*/
/**
* Event dispatched on swipe down.
* @public
* @event Swipe#swiped-down
*/
/**
* Event dispatched on swipe left.
* @public
* @event Swipe#swiped-left
*/
/**
* Event dispatched on swipe right.
* @public
* @event Swipe#swiped-right
*/
/**
* Emits events when a swipe action has occurred.
* @protected
*/
_sendEvents() {
const extentX = this.endX - this.startX;
const extentY = this.endY - this.startY;
let dir = null;
//Horizontal
if (Math.abs(extentX) > Math.abs(extentY)) {
dir = extentX > 0 ? "right" : "left";
}
//Vertical
if (Math.abs(extentX) < Math.abs(extentY)) {
dir = extentY > 0 ? "down" : "up";
}
if (dir) {
this._el.dispatchEvent( new CustomEvent('swiped', { detail: { direction: dir } }) );
this._el.dispatchEvent( new CustomEvent(`swiped-${dir}`) );
}
}
}
/**
* The configuration object for the Scroller.
* @typedef {object} scrollerConfig
@ -157,6 +247,10 @@ class Scroller {
this._sizes();
window.addEventListener('resize', this);
new Swipe(this._wrapper);
this._wrapper.addEventListener('swiped-right', () => this.left() );
this._wrapper.addEventListener('swiped-left', e => this.right() );
}
/**
@ -332,6 +426,8 @@ class Scroller {
* @property {string} [texts.download = ]
* @property {string} [texts.prev = ]
* @property {string} [texts.next = ]
* @property {string} [texts.reveal = ]
* @property {string} [texts.revealActive = ]
* @property {string} [texts.link = ]
* @property {string} [texts.zoom = 🞕]
* @property {string} [texts.zoomActive = 🞔]
@ -342,6 +438,8 @@ class Scroller {
* @property {string} [titles.download = Download this image]
* @property {string} [titles.prev = Previous image]
* @property {string} [titles.next = Next image]
* @property {string} [titles.reveal = Reveal image]
* @property {string} [titles.revealActive = Re-hide image]
* @property {string} [titles.link = More information]
* @property {string} [titles.zoom = Enlarge image (drag to move the image around)]
* @property {string} [titles.zoomActive = Reset image to fit screen]
@ -350,13 +448,15 @@ class Scroller {
/**
* The available buttons which can be set in the Image Viewer configuration.
* Note that zoom has an additional 'active' and 'disabled' state setting.
* Note that reveal and zoom have additional 'active' states, and zoom also has a 'disabled' state.
* @typedef {object} imageViewerButtons
* @property {string} [cue] - The cue shown when hovering over an image to indicate the viewer is available.
* @property {string} [hide] - The button to hide/close the viewer
* @property {string} [download] - The button to download the current image in the viewer
* @property {string} [prev] - The button to show the previous image
* @property {string} [next] - The button to show the next image
* @property {string} [reveal] - The button to reveal a blurred image
* @property {string} [revealActive] - The button to hide turn off reveal - i.e. re-blur the image.
* @property {string} [link] - The button for the image's link
* @property {string} [zoom] - The button to zoom the image to full size and activate panning
* @property {string} [zoomActive] - Properties for the zoom button when it's active
@ -379,6 +479,8 @@ const defaultImageViewerConfig = {
download: "⮋",
prev: "⮈",
next: "⮊",
reveal: "",
revealActive: "ᴓ",
link: "⛓",
zoom: "🞕",
zoomActive: "🞔",
@ -389,6 +491,8 @@ const defaultImageViewerConfig = {
download: "",
prev: "",
next: "",
reveal: "",
revealActive: "",
link: "",
zoom: "",
zoomActive: "",
@ -399,6 +503,8 @@ const defaultImageViewerConfig = {
download: "Download this image",
prev: "Previous image",
next: "Next image",
reveal: "Reveal image",
revealActive: "Blur image",
link: "More information",
zoom: "Enlarge image (drag to move the image around)",
zoomActive: "Reset image to fit screen",
@ -514,6 +620,7 @@ class ImageViewer {
el.alt = img.getAttribute("alt");
this._loader.style.visibility = "hidden";
this._updateCaption(n);
this.revealToggle(!img.dataset.hasOwnProperty("reveal") || !img.dataset.reveal == 'true');
this._updateControls();
}
}
@ -601,6 +708,17 @@ class ImageViewer {
e.currentTarget.classList.toggle("zoomed");
}
/**
* Handle click events for toggling the reveal status
* @protected
* @param {HTMLElement} e The click event
*/
reveal(e) {
const state = this._imgDisplay.style.filter.includes("blur");
this.revealToggle(state);
this.btnToggle(e.currentTarget, state);
}
/**
* Toggle the specified button on or off as specified
* @protected
@ -644,6 +762,23 @@ class ImageViewer {
pz.setStyle("cursor", "auto");
pz.destroy();
}
/**
* Set the reveal state.
* @public
* @param {boolean} [reveal = true]
*/
revealToggle(reveal = true) {
const caption = this._overlay.querySelector(".caption");
if (reveal) {
this._imgDisplay.style.filter = "";
caption.style.color = "";
} else {
this._imgDisplay.style.filter = "blur(1em)";
caption.style.color = getComputedStyle(caption).getPropertyValue('background-color');
}
}
/**
* Create the overlay and insert in the document
@ -674,8 +809,14 @@ class ImageViewer {
overlay.append(this._createControls());
overlay.addEventListener("keydown", (e) => this._shortcutsEventListener(e));
new Swipe(overlay);
overlay.addEventListener('swiped-right', () => this.prev() );
overlay.addEventListener('swiped-left', e => this.next() );
overlay.addEventListener('swiped-up', e => this.hide() );
this._overlay = overlay;
this._imgDisplay = activeImg;
this._caption = caption;
this._loader = loader;
this._active = false;
@ -738,6 +879,8 @@ class ImageViewer {
if (this._images.length > 1) {
btns.push("next", "prev");
}
btns.push("reveal");
const anchors = [ "download", "link" ];
for (const b of btns) {
@ -780,6 +923,14 @@ class ImageViewer {
}
}
const btnReveal = document.getElementById("btn-reveal");
if (this._images[i].dataset.reveal == 'true') {
btnReveal.style.display = "block";
} else {
btnReveal.style.display = "none";
}
if (this._config.panzoom) {
console.log(`Shown: ${img.width}; Actual: ${img.naturalWidth}`);
const btnZoom = document.getElementById("btn-zoom");
@ -823,4 +974,92 @@ class ImageViewer {
}
}
export { ImageViewer, Scroller };
/**
* A simple animated visibility toggler.
* @public
* @param {HTMLElement} source The element which triggers the toggle, e.g. a `<button>`
* @param {HTMLElement|null} [target = null] The element of which to toggle the visibility.
* If omitted, the `data-toggle-target` attribute of the source will be checked for an ID.
* If neither is provided, an error is thrown.
* @param {string} [toggleText = ''] The replacement text for the source when its state is toggled.
* If omitted, the `data-toggle-text` attribute of the source will be used.
* If neither is provided, the source text remains static.
*/
class Toggler {
constructor(source, target = null, toggleText = null) {
this._source = source;
try {
this._target = ( target instanceof HTMLElement ? target : document.getElementById(source.dataset.toggleTarget) );
} catch {
throw new Error(`Invalid target set. The target element must be provided either directly or with a data attribute`);
}
this._target.classList.add('toggle-view');
try {
this._toggleText = ( toggleText ? toggleText : source.dataset.toggleText );
} catch {
console.log("No toggle text");
}
this._sourceTextTarget = ( this._source.querySelector(".toggle-text") ? this._source.querySelector(".toggle-text") : this._source );
this._origText = this._sourceTextTarget.textContent;
this._source.addEventListener("click", () => this.toggle() );
}
/**
* Toggle the state of the target.
* @public
*/
toggle() {
if (this._target.classList.contains('visible')) {
this.hide();
return;
}
this.show();
}
/**
* Show the target.
* @public
*/
show() {
const target = this._target;
const height = this._checkHeight(target);
if (this._toggleText) this._sourceTextTarget.textContent = this._toggleText;
target.classList.add("visible");
target.style.height = height;
setTimeout( () => target.style.height = '', 250);
}
/**
* Hide the target.
* @public
*/
hide() {
const target = this._target;
if (this._toggleText) this._sourceTextTarget.textContent = this._origText;
target.style.height = target.scrollHeight + "px";
setTimeout( () => target.style.height = 0, 1);
setTimeout( () => target.classList.remove("visible"), 250);
}
/**
* Check the auto height of an element.
* @protected
* @param {HTMLElement} el
*/
_checkHeight(el) {
el.style.display = 'block';
const h = el.scrollHeight + "px";
el.style.display = '';
return h;
}
}
export { ImageViewer, Scroller, Toggler };

Wyświetl plik

@ -9,6 +9,8 @@ const iv = new ImageViewer({
download: "",
prev: "",
next: "",
reveal: "",
revealActive: "",
link: "",
zoom: "",
zoomActive: "",
@ -18,7 +20,9 @@ const iv = new ImageViewer({
hide: "fas fa-fw fa-times-circle",
download: "fas fa-fw fa-download",
prev: "fas fa-fw fa-chevron-circle-left",
next: "fa fa-fw fa-chevron-circle-right",
next: "fas fa-fw fa-chevron-circle-right",
reveal: "fas fa-fw fa-eye",
revealActive: "fas fa-fw fa-eye-slash",
link: "fas fa-fw fa-file-pdf",
zoom: "fas fa-fw fa-search-plus",
zoomActive: "fas fa-fw fa-search-minus",

Wyświetl plik

@ -461,7 +461,7 @@
{% if attachment.type == "Image" or (attachment | has_media_type("image")) %}
{% if attachment.url not in object.inlined_images %}
<img class="viewer" src="{{ attachment.resized_url or attachment.proxied_url }}"{% if attachment.name %} alt="{{ attachment.name }}"{% endif %} class="attachment u-photo" data-caption-id="content-{{ object.id }}" data-full="{{ attachment.proxied_url }}" />
<img class="viewer" src="{{ attachment.resized_url or attachment.proxied_url }}"{% if attachment.name %} alt="{{ attachment.name }}"{% endif %} class="attachment u-photo" data-caption-id="content-{{ object.id }}" data-full="{{ attachment.proxied_url }}" {% if object.sensitive %} data-reveal="true" {% endif %} />
{% endif %}
{% elif attachment.type == "Video" or (attachment | has_media_type("video")) %}
<div class="video-wrapper">

10
package-lock.json wygenerowano
Wyświetl plik

@ -6,20 +6,20 @@
"": {
"name": "ILA Microblog.pub assets",
"dependencies": {
"ila-ui-elements": "Aonrud/ila-ui-elements#semver:0.5.2"
"ila-ui-elements": "Aonrud/ila-ui-elements#semver:0.8.0"
}
},
"node_modules/ila-ui-elements": {
"name": "ila_ui_elements",
"version": "0.5.2",
"resolved": "git+ssh://git@github.com/Aonrud/ila-ui-elements.git#1526a617d15d57f743a13b9086e18fb39c1bc0ef",
"version": "0.8.0",
"resolved": "git+ssh://git@github.com/Aonrud/ila-ui-elements.git#0ab1b563f03183f786fdec97009fbe36f64ee50a",
"license": "GPL-3.0-or-later"
}
},
"dependencies": {
"ila-ui-elements": {
"version": "git+ssh://git@github.com/Aonrud/ila-ui-elements.git#1526a617d15d57f743a13b9086e18fb39c1bc0ef",
"from": "ila-ui-elements@Aonrud/ila-ui-elements#semver:0.5.2"
"version": "git+ssh://git@github.com/Aonrud/ila-ui-elements.git#0ab1b563f03183f786fdec97009fbe36f64ee50a",
"from": "ila-ui-elements@Aonrud/ila-ui-elements#semver:0.8.0"
}
}
}

Wyświetl plik

@ -7,6 +7,6 @@
"author": "Aonrud",
"license": "",
"dependencies": {
"ila-ui-elements": "Aonrud/ila-ui-elements#semver:0.5.2"
"ila-ui-elements": "Aonrud/ila-ui-elements#semver:0.8.0"
}
}