diff --git a/libraries/wheel-zoom.min.js b/libraries/wheel-zoom.min.js index 786680170..6f5759cd1 100644 --- a/libraries/wheel-zoom.min.js +++ b/libraries/wheel-zoom.min.js @@ -1 +1 @@ -(function(a,b){"object"==typeof exports&&"undefined"!=typeof module?module.exports=b():"function"==typeof define&&define.amd?define(b):(a="undefined"==typeof globalThis?a||self:globalThis,a.WZoom=b())})(this,function(){'use strict';var C=Math.min,D=Math.abs;function a(a,e){return b(a)||c(a,e)||d(a,e)||f()}function b(a){if(Array.isArray(a))return a}function c(a,b){var c=null==a?null:"undefined"!=typeof Symbol&&a[Symbol.iterator]||a["@@iterator"];if(null!=c){var d,e,f=[],g=!0,h=!1;try{for(c=c.call(a);!(g=(d=c.next()).done)&&(f.push(d.value),!(b&&f.length===b));g=!0);}catch(a){h=!0,e=a}finally{try{g||null==c["return"]||c["return"]()}finally{if(h)throw e}}return f}}function d(a,b){if(a){if("string"==typeof a)return e(a,b);var c=Object.prototype.toString.call(a).slice(8,-1);return"Object"===c&&a.constructor&&(c=a.constructor.name),"Map"===c||"Set"===c?Array.from(a):"Arguments"===c||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(c)?e(a,b):void 0}}function e(a,b){(null==b||b>a.length)&&(b=a.length);for(var c=0,d=Array(b);c=this.options.maxScale&&(this.options.minScale=null),this.window.$element=this.content.$element.parentNode,"image"===this.options.type){var d=!1;this.content.$element.complete&&(this._init(),d=!0),d&&!0!==this.options.watchImageChange||k(this.content.$element,"load",this._init,!this.options.watchImageChange&&{once:!0})}else this._init()}function s(a){this.options.disableWheelZoom||(a.preventDefault(),this._transform(this._computeNewPosition(this._computeNewScale(a.deltaY),{x:n(a),y:o(a)})))}function t(a){(this.isTouch&&1===a.touches.length||1===a.buttons)&&(this.coordsOnMouseDown={x:n(a),y:o(a)})}function u(a){this.coordsOnMouseDown&&this.coordsOnMouseDown.x===n(a)&&this.coordsOnMouseDown.y===o(a)&&(this._transform(this._computeNewPosition(1===this.direction?this.content.maxScale:this.content.minScale,{x:n(a),y:o(a)})),this.direction*=-1),this.coordsOnMouseDown=null}function v(a){var b=Math.round,c=Math.sqrt,d=Math.pow;if(2===a.targetTouches.length){var e=a.targetTouches[0].clientX,f=a.targetTouches[0].clientY,g=a.targetTouches[1].clientX,h=a.targetTouches[1].clientY,i=b(c(d(D(e-g),2)+d(D(f-h),2))),j=0;if(i>this.fingersHypot+5&&(j=-1),ie?-1:1;e=((d-b)/2+c)*f}}return e}function B(a){var b=g(a.$element);return{x:b.left+a.originalWidth/2-h(),y:b.top+a.originalHeight/2-i()}}return p.prototype={constructor:p,window:null,content:null,isTouch:!1,isGrab:!1,events:null,moveTimer:null,options:{},coordinates:null,speed:null,_grabHandler:function(a){(this.isTouch&&1===a.touches.length||1===a.buttons)&&(a.preventDefault(),this.isGrab=!0,this.coordinates={left:n(a),top:o(a)},this.speed={x:0,y:0},k(document,this.events.drop,this._dropHandler,this.events.options),k(document,this.events.move,this._moveHandler,this.events.options),"function"==typeof this.options.onGrab&&this.options.onGrab(a))},_dropHandler:function(a){a.preventDefault(),this.isGrab=!1,l(document,this.events.drop,this._dropHandler),l(document,this.events.move,this._moveHandler),"function"==typeof this.options.onDrop&&this.options.onDrop(a)},_moveHandler:function(a){if(this.isTouch&&1a?1:-1;var b=this.content,c=b.minScale,d=b.maxScale,e=b.currentScale,f=e+this.direction/this.options.speed;return fd&&(this.direction=-1),fd?d:f},_computeNewPosition:function(a,b){var c=b.x,d=b.y,e=this.window,f=this.content,g=f.originalWidth*a,j=f.originalHeight*a,k=h(),l=i(),m=z(c,k,e.positionLeft,f.currentLeft,e.originalWidth,g/f.currentWidth),n=z(d,l,e.positionTop,f.currentTop,e.originalHeight,j/f.currentHeight);-1===this.direction&&(m=A(this.options,e.originalWidth,f.correctX,g,m),n=A(this.options,e.originalHeight,f.correctY,j,n)),a===this.content.minScale&&(m=this.content.alignPointX,n=this.content.alignPointY);var o={currentLeft:f.currentLeft,newLeft:m,currentTop:f.currentTop,newTop:n,currentScale:f.currentScale,newScale:a};return f.currentWidth=g,f.currentHeight=j,f.currentLeft=m,f.currentTop=n,f.currentScale=a,o},_transform:function(a){a.currentLeft;var b=a.newLeft;a.currentTop;var c=a.newTop;a.currentScale;var d=a.newScale;this.options.smoothExtinction?this.content.$element.style.transition="transform ".concat(this.options.smoothExtinction,"s"):this.content.$element.style.removeProperty("transition"),this.content.$element.style.transform="translate3d(".concat(b,"px, ").concat(c,"px, 0px) scale(").concat(d,")"),"function"==typeof this.options.rescale&&this.options.rescale()},_zoom:function(a,b){(void 0===b||void 0===b.x||void 0===b.y)&&(b=B(this.window)),this._transform(this._computeNewPosition(a,b))},prepare:function(){this._prepare()},zoomUp:function(){this._zoom(this._computeNewScale(-1))},zoomDown:function(){this._zoom(this._computeNewScale(1))},maxZoomUp:function(){this._zoom(this.content.maxScale)},maxZoomDown:function(){this._zoom(this.content.minScale)},zoomUpToPoint:function(a){this._zoom(this._computeNewScale(-1),a)},zoomDownToPoint:function(a){this._zoom(this._computeNewScale(1),a)},maxZoomUpToPoint:function(a){this._zoom(this.content.maxScale,a)},setDragScrollable:function(a){this.dragScrollable=a},destroy:function(){for(var a in this.content.$element.style.transform="","image"===this.options.type&&l(this.content.$element,"load",this._init),this.isTouch&&(l(this.content.$element,"touchmove",this._zoomTwoFingers_TouchmoveHandler),l(this.content.$element,"touchend",this._zoomTwoFingers_TouchendHandler)),l(this.content.$element,"wheel",this._wheelHandler),this.options.zoomOnClick&&(l(this.content.$element,this.events.down,this._downHandler,this.events.options),l(this.content.$element,this.events.up,this._upHandler,this.events.options)),this.dragScrollable&&this.dragScrollable.destroy(),this)this.hasOwnProperty(a)&&(this[a]=null)}},r.create=function(a,b){return new r(a,b)},r}); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).WZoom=e()}(this,(function(){"use strict";function t(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(t);e&&(o=o.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,o)}return n}function e(e){for(var n=1;nt.length)&&(e=t.length);for(var n=0,o=new Array(e);n=t.length?{done:!0}:{done:!1,value:t[o++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,s=!0,c=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){c=!0,r=t},f:function(){try{s||null==n.return||n.return()}finally{if(c)throw r}}}}function g(t){var e=function(t,e){if("object"!=typeof t||null===t)return t;var n=t[Symbol.toPrimitive];if(void 0!==n){var o=n.call(t,e||"default");if("object"!=typeof o)return o;throw new TypeError("@@toPrimitive must return a primitive value.")}return("string"===e?String:Number)(t)}(t,"string");return"symbol"==typeof e?e:String(e)}function v(t){var e=t.getBoundingClientRect(),n=document,o=n.body,i=n.documentElement,r=b(),s=y(),c=i.clientTop||o.clientTop||0,a=i.clientLeft||o.clientLeft||0;return{top:e.top+r-c,left:e.left+s-a}}function y(){var t=void 0!==window.pageXOffset,e="CSS1Compat"===(document.compatMode||"");return t?window.pageXOffset:e?document.documentElement.scrollLeft:document.body.scrollLeft}function b(){var t=void 0!==window.pageYOffset,e="CSS1Compat"===(document.compatMode||"");return t?window.pageYOffset:e?document.documentElement.scrollTop:document.body.scrollTop}function _(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];t.addEventListener(e,n,o)}function w(t,e,n){var o=arguments.length>3&&void 0!==arguments[3]&&arguments[3];t.removeEventListener(e,n,o)}function H(){return"ontouchstart"in window||navigator.MaxTouchPoints>0||navigator.msMaxTouchPoints>0}function O(t){return"wheel"===t.type||"pointerup"===t.type||"pointerdown"===t.type||"pointermove"===t.type||"mousedown"===t.type||"mousemove"===t.type||"mouseup"===t.type?t.clientX:t.changedTouches[0].clientX}function S(t){return"wheel"===t.type||"pointerup"===t.type||"pointerdown"===t.type||"pointermove"===t.type||"mousedown"===t.type||"mousemove"===t.type||"mouseup"===t.type?t.clientY:t.changedTouches[0].clientY}function T(t,e,n,o,i,r){var s=i/2-(t+e-n)+o;return s*r-s+o}function P(t,e,n,o,i){switch(t){case"left":o/2-i1)return!1;var n=this.coordinatesShift,o=this.coordinates;n.x=O(t)-o.x,n.y=S(t)-o.y,o.x=O(t),o.y=S(t),clearTimeout(this.moveTimer),this.moveTimer=setTimeout((function(){n.x=0,n.y=0}),50),t.data=e(e({},t.data||{}),{},{x:n.x,y:n.y}),this._run(W,t)}}]),r}(j),$="click",E="dblclick",z="wheel",C=function(t){s(o,t);var e=u(o);function o(t){var i;return n(this,o),(i=e.call(this)).target=t,i.coordsOnDown=null,i.pressingTimeout=null,i.firstClick=!0,i.isTouch=H(),i.events=i.isTouch?{down:"touchstart",up:"touchend"}:{down:"mousedown",up:"mouseup"},i.events.options=!!i.isTouch&&{passive:!0},i._downHandler=i._downHandler.bind(l(i)),i._upHandler=i._upHandler.bind(l(i)),i._wheelHandler=i._wheelHandler.bind(l(i)),_(i.target,i.events.down,i._downHandler,i.events.options),_(i.target,i.events.up,i._upHandler,i.events.options),_(i.target,z,i._wheelHandler),i}return i(o,[{key:"destroy",value:function(){w(this.target,this.events.down,this._downHandler,this.events.options),w(this.target,this.events.up,this._upHandler,this.events.options),w(this.target,z,this._wheelHandler,this.events.options),h(c(o.prototype),"destroy",this).call(this)}},{key:"_downHandler",value:function(t){this.coordsOnDown=null,(this.isTouch&&1===t.touches.length||1===t.buttons)&&(this.coordsOnDown={x:O(t),y:S(t)}),clearTimeout(this.pressingTimeout)}},{key:"_upHandler",value:function(t){var e=this,n=this.subscribes[E]?200:0;this.firstClick?(this.pressingTimeout=setTimeout((function(){e.coordsOnDown&&e.coordsOnDown.x===O(t)&&e.coordsOnDown.y===S(t)&&e._run($,t),e.firstClick=!0}),n),this.firstClick=!1):this.pressingTimeout=setTimeout((function(){e._run(E,t),e.firstClick=!0}),n/2)}},{key:"_wheelHandler",value:function(t){this._run(z,t)}}]),o}(j),L="pinchtozoom",Y=function(t){s(r,t);var o=u(r);function r(t){var e;return n(this,r),(e=o.call(this)).target=t,e.fingersHypot=null,e.zoomPinchWasDetected=!1,e._touchMoveHandler=e._touchMoveHandler.bind(l(e)),e._touchEndHandler=e._touchEndHandler.bind(l(e)),_(e.target,"touchmove",e._touchMoveHandler),_(e.target,"touchend",e._touchEndHandler),e}return i(r,[{key:"destroy",value:function(){w(this.target,"touchmove",this._touchMoveHandler),w(this.target,"touchend",this._touchEndHandler),h(c(r.prototype),"destroy",this).call(this)}},{key:"_touchMoveHandler",value:function(t){if(2===t.targetTouches.length){var n=t.targetTouches[0].clientX,o=t.targetTouches[0].clientY,i=t.targetTouches[1].clientX,r=t.targetTouches[1].clientY,s=Math.round(Math.sqrt(Math.pow(Math.abs(n-i),2)+Math.pow(Math.abs(o-r),2))),c=0;if(s>this.fingersHypot+5&&(c=-1),s1&&void 0!==arguments[1]?arguments[1]:{};if(this._init=this._init.bind(this),this._prepare=this._prepare.bind(this),this._computeScale=this._computeScale.bind(this),this._computePosition=this._computePosition.bind(this),this._transform=this._transform.bind(this),this.content={},"string"==typeof t)this.content.$element=document.querySelector(t);else{if(!(t instanceof HTMLElement))throw"WZoom: `selectorOrHTMLElement` must be selector or HTMLElement, and not ".concat({}.toString.call(t));this.content.$element=t}this.content.$element&&(this.viewport={},this.viewport.$element=this.content.$element.parentElement,this.options=function(t,e){var n=Object.assign({},e,t);n.dragScrollableOptions=Object.assign({},n.dragScrollableOptions),n.smoothTime=Number(n.smoothTime)||x.smoothTime,H()&&(n.smoothTime=0);return n}(e,x),this.isTouch=H(),this.direction=1,this.observers=[],"image"===this.options.type?this.content.$element.complete?this._init():_(this.content.$element,"load",this._init,{once:!0}):this._init())}return X.prototype={constructor:X,_init:function(){var t=this,e=this.viewport,n=this.content,o=this.options,i=this.observers;if(this._prepare(),this._destroyObservers(),!0===o.dragScrollable){var r=new D(n.$element);i.push(r),"function"==typeof o.dragScrollableOptions.onGrab&&r.on(k,(function(e){e.preventDefault(),o.dragScrollableOptions.onGrab(e,t)})),"function"==typeof o.dragScrollableOptions.onDrop&&r.on(M,(function(e){e.preventDefault(),o.dragScrollableOptions.onDrop(e,t)})),r.on(W,(function(i){i.preventDefault();var r=i.data,s=r.x,c=r.y,a=n.currentLeft+s,l=n.currentTop+c,u=(n.currentWidth-e.originalWidth)/2+n.correctX,h=(n.currentHeight-e.originalHeight)/2+n.correctY;Math.abs(a)<=u&&(n.currentLeft=a),Math.abs(l)<=h&&(n.currentTop=l),t._transform(),"function"==typeof o.dragScrollableOptions.onMove&&o.dragScrollableOptions.onMove(i,t)}))}var s=new C(n.$element);if(i.push(s),!o.disableWheelZoom)if(this.isTouch){var c=new Y(n.$element);i.push(c),c.on(L,(function(e){var n=e.data,o=n.clientX,i=n.clientY,r=n.direction,s=t._computeScale(r);t._computePosition(s,o,i),t._transform()}))}else s.on(z,(function(e){e.preventDefault();var n=o.reverseWheelDirection?-e.deltaY:e.deltaY,i=t._computeScale(n);t._computePosition(i,O(e),S(e)),t._transform()}));if(o.zoomOnClick||o.zoomOnDblClick){var a=o.zoomOnDblClick?E:$;s.on(a,(function(e){var o=1===t.direction?n.maxScale:n.minScale;t._computePosition(o,O(e),S(e)),t._transform(),t.direction*=-1}))}},_prepare:function(){var t=this.viewport,e=this.content,n=this.options,o=v(t.$element),i=o.left,r=o.top;t.originalWidth=t.$element.offsetWidth,t.originalHeight=t.$element.offsetHeight,t.originalLeft=i,t.originalTop=r,"image"===n.type?(e.originalWidth=n.width||e.$element.naturalWidth,e.originalHeight=n.height||e.$element.naturalHeight):(e.originalWidth=n.width||e.$element.offsetWidth,e.originalHeight=n.height||e.$element.offsetHeight),e.maxScale=n.maxScale,e.minScale=n.minScale||Math.min(t.originalWidth/e.originalWidth,t.originalHeight/e.originalHeight,e.maxScale),e.currentScale=e.minScale,e.currentWidth=e.originalWidth*e.currentScale,e.currentHeight=e.originalHeight*e.currentScale;var s=function(t,e,n){var o=0,i=0;switch(n){case"top":i=(e.currentHeight-t.originalHeight)/2;break;case"right":o=(e.currentWidth-t.originalWidth)/2*-1;break;case"bottom":i=(e.currentHeight-t.originalHeight)/2*-1;break;case"left":o=(e.currentWidth-t.originalWidth)/2}return[o,i]}(t,e,n.alignContent),c=f(s,2);e.alignPointX=c[0],e.alignPointY=c[1],e.currentLeft=e.alignPointX,e.currentTop=e.alignPointY;var a=function(t,e,n){var o=Math.max(0,(t.originalWidth-e.currentWidth)/2),i=Math.max(0,(t.originalHeight-e.currentHeight)/2);switch(n){case"top":i=0;break;case"right":o=0;break;case"bottom":i*=2;break;case"left":o*=2}return[o,i]}(t,e,n.alignContent),l=f(a,2);e.correctX=l[0],e.correctY=l[1],"function"==typeof n.prepare&&n.prepare(this),this._transform()},_computeScale:function(t){this.direction=t<0?1:-1;var e=this.content,n=e.minScale,o=e.maxScale,i=e.currentScale*Math.pow(this.options.speed,this.direction);return i<=n?(this.direction=1,n):i>=o?(this.direction=-1,o):i},_computePosition:function(t,e,n){var o=this.viewport,i=this.content,r=this.options,s=this.direction,c=i.originalWidth*t,a=i.originalHeight*t,l=y(),u=b(),h=T(e,l,o.originalLeft,i.currentLeft,o.originalWidth,c/i.currentWidth),f=T(n,u,o.originalTop,i.currentTop,o.originalHeight,a/i.currentHeight);-1===s&&(h=P(r.alignContent,o.originalWidth,i.correctX,c,h),f=P(r.alignContent,o.originalHeight,i.correctY,a,f)),t===i.minScale&&(h=i.alignPointX,f=i.alignPointY),i.currentWidth=c,i.currentHeight=a,i.currentLeft=h,i.currentTop=f,i.currentScale=t},_transform:function(){var t,e;t=this.content.$element,(e=this.options.smoothTime)?t.style.transition="transform ".concat(e,"s"):t.style.removeProperty("transition"),function(t,e,n,o){t.style.transform="translate(".concat(e,"px, ").concat(n,"px) scale(").concat(o,")")}(this.content.$element,this.content.currentLeft,this.content.currentTop,this.content.currentScale),"function"==typeof this.options.rescale&&this.options.rescale(this)},_zoom:function(t){var e,n,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};void 0!==o.x&&void 0!==o.y||(e=this.viewport,o={x:(n=v(e.$element)).left+e.originalWidth/2-y(),y:n.top+e.originalHeight/2-b()}),this._computePosition(t,o.x,o.y),this._transform()},_destroyObservers:function(){var t,e=m(this.observers);try{for(e.s();!(t=e.n()).done;){t.value.destroy()}}catch(t){e.e(t)}finally{e.f()}},prepare:function(){this._prepare()},transform:function(t,e,n){var o=this.content;o.currentWidth=o.originalWidth*n,o.currentHeight=o.originalHeight*n,o.currentLeft=e,o.currentTop=t,o.currentScale=n,this._transform()},zoomUp:function(){this._zoom(this._computeScale(-1))},zoomDown:function(){this._zoom(this._computeScale(1))},maxZoomUp:function(){this._zoom(this.content.maxScale)},maxZoomDown:function(){this._zoom(this.content.minScale)},zoomUpToPoint:function(t){this._zoom(this._computeScale(-1),t)},zoomDownToPoint:function(t){this._zoom(this._computeScale(1),t)},maxZoomUpToPoint:function(t){this._zoom(this.content.maxScale,t)},destroy:function(){for(var t in this.content.$element.style.removeProperty("transition"),this.content.$element.style.removeProperty("transform"),"image"===this.options.type&&w(this.content.$element,"load",this._init),this._destroyObservers(),this)this.hasOwnProperty(t)&&(this[t]=null)}},X.create=function(t){return new X(t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:{})},X})); diff --git a/src/public/app/services/content_renderer.js b/src/public/app/services/content_renderer.js index 01234fc1c..b51be52ee 100644 --- a/src/public/app/services/content_renderer.js +++ b/src/public/app/services/content_renderer.js @@ -35,7 +35,7 @@ async function getRenderedContent(entity, options = {}) { await renderCode(entity, options, $renderedContent); } else if (type === 'image') { - renderImage(entity, $renderedContent); + renderImage(entity, $renderedContent, options); } else if (!options.tooltip && ['file', 'pdf', 'audio', 'video'].includes(type)) { renderFile(entity, type, $renderedContent); @@ -118,7 +118,7 @@ async function renderCode(note, options, $renderedContent) { $renderedContent.append($("
").text(trim(blob.content, options.trim)));
 }
 
-function renderImage(entity, $renderedContent) {
+function renderImage(entity, $renderedContent, options = {}) {
     const sanitizedTitle = entity.title.replace(/[^a-z0-9-.]/gi, "");
 
     let url;
@@ -129,11 +129,27 @@ function renderImage(entity, $renderedContent) {
         url = `api/attachments/${entity.attachmentId}/image/${sanitizedTitle}?${entity.utcDateModified}">`;
     }
 
-    $renderedContent.append(
-        $("")
-            .attr("src", url)
-            .css("max-width", "100%")
-    );
+    $renderedContent // styles needed for the zoom to work well
+        .css('display', 'flex')
+        .css('align-items', 'center')
+        .css('justify-content', 'center');
+
+    const $img = $("")
+        .attr("src", url)
+        .attr("id", "attachment-image-" + idCounter++)
+        .css("max-width", "100%");
+
+    $renderedContent.append($img);
+
+    if (options.imageHasZoom) {
+        libraryLoader.requireLibrary(libraryLoader.WHEEL_ZOOM).then(() => {
+            WZoom.create(`#${$img.attr("id")}`, {
+                maxScale: 10,
+                speed: 20,
+                zoomOnClick: false
+            });
+        });
+    }
 }
 
 function renderFile(entity, type, $renderedContent) {
diff --git a/src/public/app/widgets/attachment_detail.js b/src/public/app/widgets/attachment_detail.js
index d9de70301..4ca6eff6d 100644
--- a/src/public/app/widgets/attachment_detail.js
+++ b/src/public/app/widgets/attachment_detail.js
@@ -167,7 +167,9 @@ export default class AttachmentDetailWidget extends BasicWidget {
         this.$wrapper.find('.attachment-details')
             .text(`Role: ${this.attachment.role}, Size: ${utils.formatSize(this.attachment.contentLength)}`);
         this.$wrapper.find('.attachment-actions-container').append(this.attachmentActionsWidget.render());
-        this.$wrapper.find('.attachment-content-wrapper').append((await contentRenderer.getRenderedContent(this.attachment)).$renderedContent);
+
+        const {$renderedContent} = await contentRenderer.getRenderedContent(this.attachment, { imageHasZoom: true });
+        this.$wrapper.find('.attachment-content-wrapper').append($renderedContent);
     }
 
     async copyAttachmentLinkToClipboard() {