Minipreview jQuery link preview contents of parent <p> or <div> only

504 Views Asked by At

I'd like to use https://github.com/lonekorean/mini-preview to create mouseover previews for parts of a website only.

I have no problems using anchors from the target website to have the script render a full website preview, scrolled to where an individual anchor is. That's not what I'm after however.

I'd like the script to show only the content of the anchors' parent <p> or <div>.

On the site, the link target anchors are coded like this:

<div class="paragraph">
    <p>
        <a id="anchor_1"></a>
        Foo bar baz.
    </p>
</div>

So, I'd like the little preview box to show Foo bar baz. only.

I suspect the answer lies in this part of the script:

loadPreview: function() {
    this.$el.find('.' + PREFIX + '-frame')
        .attr('src', this.$el.attr('href'))
        .on('load', function() {
            // some sites don't set their background color
            $(this).css('background-color', '#fff');
});

specifically, the .attr('src', this.$el.attr('href')) part. I'm not sure though.

Does anyone know how I can do this?
Or can you recommend some other script that I can use to do this and makes things look as nice as this one?

I'm not a web dev, so please go easy on me.
Thanks

UPDATE (based on Swati's answer and corresponding comments):

For example, if my website includes this:

<body>
    <p>
        <a href="#anchor_on_my_site">See internal</a>
    </p>
    <p>
        <a href="external_website.html#external_anchor">See external</a>
    </p>
    <div class="paragraph">
        <p>
            <a id="anchor_on_my_site"></a>
                Foo bar baz.
        </p>
    </div>
</body>

and the external website includes this:

<body>
    <div class="paragraph">
        <p>
            <a id="external_anchor"></a>
                Qux quux quuz.
        </p>
    </div>
</body>

I'd like See internal to display Foo bar baz. and See external to display Qux quux quuz.

1

There are 1 best solutions below

8
On BEST ANSWER

Inside loadPreview function you can use closest('p').clone().children().remove().end().text() to get text from p tag where a has been hover then using this put that text to show inside your frame div i.e : .find('.' + PREFIX + '-frame').text(data_to_show) .

Demo Code :

(function($) {
  var PREFIX = 'mini-preview';

  $.fn.miniPreview = function(options) {
    return this.each(function() {
      var $this = $(this);
      var miniPreview = $this.data(PREFIX);
      if (miniPreview) {
        miniPreview.destroy();
      }

      miniPreview = new MiniPreview($this, options);
      miniPreview.generate();
      $this.data(PREFIX, miniPreview);
    });
  };

  var MiniPreview = function($el, options) {
    this.$el = $el;
    this.$el.addClass(PREFIX + '-anchor');
    this.options = $.extend({}, this.defaultOptions, options);
    this.counter = MiniPreview.prototype.sharedCounter++;
  };

  MiniPreview.prototype = {
    sharedCounter: 0,

    defaultOptions: {
      width: 256,
      height: 144,
      scale: .25,
      prefetch: 'parenthover'
    },

    generate: function() {
      this.createElements();
      this.setPrefetch();
    },

    createElements: function() {
      var $wrapper = $('<div>', {
        class: PREFIX + '-wrapper'
      });
      //no need to use iframe...use simple div 
      var $frame = $('<div>', {
        class: PREFIX + '-frame'
      });
      var $cover = $('<div>', {
        class: PREFIX + '-cover'
      });
      $wrapper.appendTo(this.$el).append($frame, $cover);

      // sizing
      $wrapper.css({
        width: this.options.width + 'px',
        height: this.options.height + 'px'
      });

      // scaling
      var inversePercent = 100 / this.options.scale;
      $frame.css({
        width: inversePercent + '%',
        height: inversePercent + '%',
        transform: 'scale(' + this.options.scale + ')'
      });
      var fontSize = parseInt(this.$el.css('font-size').replace('px', ''), 10)
      var top = (this.$el.height() + fontSize) / 2;
      var left = (this.$el.width() - $wrapper.outerWidth()) / 2;
      //add more style here ...if needed to outer div
      $wrapper.css({
        top: top + 'px',
        left: left + 'px',
        'font-size': '55px',
        'color': 'blue'
      });
    },

    setPrefetch: function() {
      switch (this.options.prefetch) {
        case 'pageload':
          this.loadPreview();
          break;
        case 'parenthover':
          this.$el.parent().one(this.getNamespacedEvent('mouseenter'),
            this.loadPreview.bind(this));
          break;
        case 'none':
          this.$el.one(this.getNamespacedEvent('mouseenter'),
            this.loadPreview.bind(this));
          break;
        default:
          throw 'Prefetch setting not recognized: ' + this.options.prefetch;
          break;
      }
    },

    loadPreview: function() {
      //to get text from p tag
      var data_to_show = this.$el.closest('p').clone().children().remove().end().text().trim()
      //set new text inside div frame
      this.$el.find('.' + PREFIX + '-frame').text(data_to_show)
      //set bg color..
      this.$el.find('.' + PREFIX + '-frame').css('background-color', '#fff');


    },

    getNamespacedEvent: function(event) {
      return event + '.' + PREFIX + '_' + this.counter;
    },

    destroy: function() {
      this.$el.removeClass(PREFIX + '-anchor');
      this.$el.parent().off(this.getNamespacedEvent('mouseenter'));
      this.$el.off(this.getNamespacedEvent('mouseenter'));
      this.$el.find('.' + PREFIX + '-wrapper').remove();

    }
  };
})(jQuery);


$('a').miniPreview();
body {
  height: 100%;
  margin: 0;
  padding: 0 10% 40px;
  font-size: 2rem;
  line-height: 1.5;
  font-family: 'Roboto Slab', sans-serif;
  text-align: justify;
  color: #59513f;
  background-color: #f5ead4;
}

a {
  color: #537f7c;
}

.mini-preview-anchor {
  display: inline-block;
  position: relative;
  white-space: nowrap;
}

.mini-preview-wrapper {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  position: absolute;
  overflow: hidden;
  z-index: -1;
  opacity: 0;
  margin-top: -4px;
  border: solid 1px #000;
  box-shadow: 4px 4px 6px rgba(0, 0, 0, .3);
  transition: z-index steps(1) .3s, opacity .3s, margin-top .3s;
}

.mini-preview-anchor:hover .mini-preview-wrapper {
  z-index: 2;
  opacity: 1;
  margin-top: 6px;
  transition: opacity .3s, margin-top .3s;
}

.mini-preview-cover {
  background-color: rgba(0, 0, 0, 0);
  /* IE fix */
}

.mini-preview-frame {
  border: none;
  -webkit-transform-origin: 0 0;
  transform-origin: 0 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>

<body>
  <div class="paragraph">
    <p>
      <a id="anchor_1">See</a> This is text we are showing for first
    </p>
    <p>
      <a id="anchor_2">See</a> This is text we are showing for second
    </p>
  </div>
</body>

</html>

Update 1 :

You can differentiate between external & internal link using some class i.e : simply check if the a tag which is hover has a particular class or not depending on this change your code to preview divs.

Updated Code :

if (this.$el.hasClass("internal")) {
        //to get text from p tag
        var data_to_show = this.$el.closest('p').siblings(".paragraph").clone().text().trim()
        //set new text inside div frame
        this.$el.find('.' + PREFIX + '-frame').text(data_to_show)
        //set bg color..
        this.$el.find('.' + PREFIX + '-frame').css('background-color', '#fff');
} else {       
        console.log("for external code ..")    
}