text: jQuery(document).ready(function ($) {
  
      var productViewer = function (element) {
          this.element = element;
          this.handleContainer = this.element.find('.cd-product-viewer-handle');
          this.handleFill = this.handleContainer.children('.fill');
          this.handle = this.handleContainer.children('.handle');
          this.imageWrapper = this.element.find('.product-viewer');
          this.slideShow = this.imageWrapper.children('.product-sprite');
          this.frames = this.element.data('frame');
          //increase this value to increase the friction while dragging on the image - it has to be bigger than zero
          this.friction = this.element.data('friction');
          this.visibleFrame = 0;
          this.loaded = false;
          this.animating = false;
          this.xPosition = 0;
          this.loadFrames();
      }
  
      productViewer.prototype.loadFrames = function () {
          var self = this,
              imageUrl = this.slideShow.data('image'),
              newImg = $('<img/>');
          this.loading('0.5');
          //you need this to check if the image sprite has been loaded
          newImg.attr('src', imageUrl).load(function () {
              $(this).remove();
              self.loaded = true;
          }).each(function () {
              image = this;
              if (image.complete) {
                  $(image).trigger('load');
              }
          });
      }
  
      productViewer.prototype.loading = function (percentage) {
          var self = this;
          transformElement(this.handleFill, 'scaleX(' + percentage + ')');
          setTimeout(function () {
              if (self.loaded) {
                  //sprite image has been loaded
                  self.element.addClass('loaded');
                  transformElement(self.handleFill, 'scaleX(1)');
                  self.dragImage();
                  if (self.handle) self.dragHandle();
              } else {
                  //sprite image has not been loaded - increase self.handleFill scale value
                  var newPercentage = parseFloat(percentage) + .1;
                  if (newPercentage < 1) {
                      self.loading(newPercentage);
                  } else {
                      self.loading(parseFloat(percentage));
                  }
              }
          }, 500);
      }
      //draggable funtionality - credits to http://css-tricks.com/snippets/jquery/draggable-without-jquery-ui/
      productViewer.prototype.dragHandle = function () {
          //implement handle draggability
          var self = this;
          self.handle.on('mousedown vmousedown', function (e) {
              self.handle.addClass('cd-draggable');
              var dragWidth = self.handle.outerWidth(),
                  containerOffset = self.handleContainer.offset().left,
                  containerWidth = self.handleContainer.outerWidth(),
                  minLeft = containerOffset - dragWidth / 2,
                  maxLeft = containerOffset + containerWidth - dragWidth / 2;
  
              self.xPosition = self.handle.offset().left + dragWidth - e.pageX;
  
              self.element.on('mousemove vmousemove', function (e) {
                  if (!self.animating) {
                      self.animating = true;
                      (!window.requestAnimationFrame) ?
                      setTimeout(function () {
                          self.animateDraggedHandle(e, dragWidth, containerOffset, containerWidth, minLeft, maxLeft);
                      }, 100): requestAnimationFrame(function () {
                          self.animateDraggedHandle(e, dragWidth, containerOffset, containerWidth, minLeft, maxLeft);
                      });
                  }
              }).one('mouseup vmouseup', function (e) {
                  self.handle.removeClass('cd-draggable');
                  self.element.off('mousemove vmousemove');
              });
  
              e.preventDefault();
  
          }).on('mouseup vmouseup', function (e) {
              self.handle.removeClass('cd-draggable');
          });
      }
  
      productViewer.prototype.animateDraggedHandle = function (e, dragWidth, containerOffset, containerWidth, minLeft, maxLeft) {
          var self = this;
          var leftValue = e.pageX + self.xPosition - dragWidth;
          // constrain the draggable element to move inside his container
          if (leftValue < minLeft) {
              leftValue = minLeft;
          } else if (leftValue > maxLeft) {
              leftValue = maxLeft;
          }
  
          var widthValue = Math.ceil((leftValue + dragWidth / 2 - containerOffset) * 1000 / containerWidth) / 10;
          self.visibleFrame = Math.ceil((widthValue * (self.frames - 1)) / 100);
  
          //update image frame
          self.updateFrame();
          //update handle position
          $('.cd-draggable', self.handleContainer).css('left', widthValue + '%').one('mouseup vmouseup', function () {
              $(this).removeClass('cd-draggable');
          });
  
          self.animating = false;
      }
  
      productViewer.prototype.dragImage = function () {
          //implement image draggability
          var self = this;
          self.slideShow.on('mousedown vmousedown', function (e) {
              self.slideShow.addClass('cd-draggable');
              var containerOffset = self.imageWrapper.offset().left,
                  containerWidth = self.imageWrapper.outerWidth(),
                  minFrame = 0,
                  maxFrame = self.frames - 1;
  
              self.xPosition = e.pageX;
  
              self.element.on('mousemove vmousemove', function (e) {
                  if (!self.animating) {
                      self.animating = true;
                      (!window.requestAnimationFrame) ?
                      setTimeout(function () {
                          self.animateDraggedImage(e, containerOffset, containerWidth);
                      }, 100): requestAnimationFrame(function () {
                          self.animateDraggedImage(e, containerOffset, containerWidth);
                      });
                  }
              }).one('mouseup vmouseup', function (e) {
                  self.slideShow.removeClass('cd-draggable');
                  self.element.off('mousemove vmousemove');
                  self.updateHandle();
              });
  
              e.preventDefault();
  
          }).on('mouseup vmouseup', function (e) {
              self.slideShow.removeClass('cd-draggable');
          });
      }
  
      productViewer.prototype.animateDraggedImage = function (e, containerOffset, containerWidth) {
          var self = this;
          var leftValue = self.xPosition - e.pageX;
          var widthValue = Math.ceil((leftValue) * 100 / (containerWidth * self.friction));
          var frame = (widthValue * (self.frames - 1)) / 100;
          if (frame > 0) {
              frame = Math.floor(frame);
          } else {
              frame = Math.ceil(frame);
          }
          var newFrame = self.visibleFrame + frame;
  
          if (newFrame < 0) {
              newFrame = self.frames - 1;
          } else if (newFrame > self.frames - 1) {
              newFrame = 0;
          }
  
          if (newFrame != self.visibleFrame) {
              self.visibleFrame = newFrame;
              self.updateFrame();
              self.xPosition = e.pageX;
          }
  
          self.animating = false;
      }
  
      productViewer.prototype.updateHandle = function () {
          if (this.handle) {
              var widthValue = 100 * this.visibleFrame / this.frames;
              this.handle.animate({
                  'left': widthValue + '%'
              }, 200);
          }
      }
  
      productViewer.prototype.updateFrame = function () {
          var transformValue = -(100 * this.visibleFrame / this.frames);
          transformElement(this.slideShow, 'translateX(' + transformValue + '%)');
      }
  
      function transformElement(element, value) {
          element.css({
              '-moz-transform': value,
              '-webkit-transform': value,
              '-ms-transform': value,
              '-o-transform': value,
              'transform': value,
          });
      }
  
      var productToursWrapper = $('.cd-product-viewer-wrapper');
      productToursWrapper.each(function () {
          new productViewer($(this));
      });
  });