odoo.define('website.content.zoomodoo', function (require) { 'use strict'; /** This code has been more that widely inspired by easyZoom library. Copyright 2013 Matt Hinchliffe Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. **/ var dw, dh, rw, rh, lx, ly; var defaults = { // Attribute to retrieve the zoom image URL from. linkTag: 'a', linkAttribute: 'data-zoom-image', // event to trigger zoom event: 'click', //or mouseenter // Prevent clicks on the zoom image link. preventClicks: true, // disable on mobile disabledOnMobile: true, // Callback function to execute before the flyout is displayed. beforeShow: $.noop, // Callback function to execute before the flyout is removed. beforeHide: $.noop, // Callback function to execute when the flyout is displayed. onShow: $.noop, // Callback function to execute when the flyout is removed. onHide: $.noop, // Callback function to execute when the cursor is moved while over the image. onMove: $.noop }; /** * ZoomOdoo * @constructor * @param {Object} target * @param {Object} options (Optional) */ function ZoomOdoo(target, options) { this.$target = $(target); this.opts = $.extend({}, defaults, options, this.$target.data()); if (this.isOpen === undefined) { this._init(); } } /** * Init * @private */ ZoomOdoo.prototype._init = function () { if (window.outerWidth > 467 || !this.opts.disabledOnMobile) { this.$link = this.$target.find(this.opts.linkTag).length && this.$target.find(this.opts.linkTag) || this.$target; this.$image = this.$target.find('img').length && this.$target.find('img') || this.$target; this.$flyout = $('
'); var $attach = this.$target; if (this.opts.attach !== undefined && this.$target.parents(this.opts.attach).length) { $attach = this.$target.parents(this.opts.attach); } $attach.parent().on('mousemove.zoomodoo touchmove.zoomodoo', $.proxy(this._onMove, this)); $attach.parent().on('mouseleave.zoomodoo touchend.zoomodoo', $.proxy(this._onLeave, this)); this.$target.on(this.opts.event + '.zoomodoo touchstart.zoomodoo', $.proxy(this._onEnter, this)); if (this.opts.preventClicks) { this.$target.on('click.zoomodoo', function (e) { e.preventDefault(); }); } } }; /** * Show * @param {MouseEvent|TouchEvent} e * @param {Boolean} testMouseOver (Optional) */ ZoomOdoo.prototype.show = function (e, testMouseOver) { var w1, h1, w2, h2; var self = this; if (this.opts.beforeShow.call(this) === false) return; if (!this.isReady) { return this._loadImage(this.$link.attr(this.opts.linkAttribute), function () { if (self.isMouseOver || !testMouseOver) { self.show(e); } }); } var $attach = this.$target; if (this.opts.attach !== undefined && this.$target.parents(this.opts.attach).length) { $attach = this.$target.parents(this.opts.attach); } $attach.parent().append(this.$flyout); w1 = this.$target.width(); h1 = this.$target.height(); w2 = this.$flyout.width(); h2 = this.$flyout.height(); dw = this.$zoom.width() - w2; dh = this.$zoom.height() - h2; // For the case where the zoom image is actually smaller than // the flyout. if (dw < 0) dw = 0; if (dh < 0) dh = 0; rw = dw / w1; rh = dh / h1; this.isOpen = true; this.opts.onShow.call(this); if (e) { this._move(e); } }; /** * On enter * @private * @param {Event} e */ ZoomOdoo.prototype._onEnter = function (e) { var touches = e.originalEvent.touches; this.isMouseOver = true; if (!touches || touches.length === 1) { e.preventDefault(); this.show(e, true); } }; /** * On move * @private * @param {Event} e */ ZoomOdoo.prototype._onMove = function (e) { if (!this.isOpen) return; e.preventDefault(); this._move(e); }; /** * On leave * @private */ ZoomOdoo.prototype._onLeave = function () { this.isMouseOver = false; if (this.isOpen) { this.hide(); } }; /** * On load * @private * @param {Event} e */ ZoomOdoo.prototype._onLoad = function (e) { // IE may fire a load event even on error so test the image dimensions if (!e.currentTarget.width) return; this.isReady = true; this.$flyout.html(this.$zoom); if (e.data.call) { e.data(); } }; /** * Load image * @private * @param {String} href * @param {Function} callback */ ZoomOdoo.prototype._loadImage = function (href, callback) { var zoom = new Image(); this.$zoom = $(zoom).on('load', callback, $.proxy(this._onLoad, this)); zoom.style.position = 'absolute'; zoom.src = href; }; /** * Move * @private * @param {Event} e */ ZoomOdoo.prototype._move = function (e) { if (e.type.indexOf('touch') === 0) { var touchlist = e.touches || e.originalEvent.touches; lx = touchlist[0].pageX; ly = touchlist[0].pageY; } else { lx = e.pageX || lx; ly = e.pageY || ly; } var offset = this.$target.offset(); var pt = ly - offset.top; var pl = lx - offset.left; var xt = Math.ceil(pt * rh); var xl = Math.ceil(pl * rw); // Close if outside if (xl < 0 || xt < 0 || xl > dw || xt > dh) { this.hide(); } else { var top = xt * -1; var left = xl * -1; this.$zoom.css({ top: top, left: left }); this.opts.onMove.call(this, top, left); } }; /** * Hide */ ZoomOdoo.prototype.hide = function () { if (!this.isOpen) return; if (this.opts.beforeHide.call(this) === false) return; this.$flyout.detach(); this.isOpen = false; this.opts.onHide.call(this); }; // jQuery plugin wrapper $.fn.zoomOdoo = function (options) { return this.each(function () { var api = $.data(this, 'zoomOdoo'); if (!api) { $.data(this, 'zoomOdoo', new ZoomOdoo(this, options)); } else if (api.isOpen === undefined) { api._init(); } }); }; });