Multiple instances of plugin being called wonks out

I’m using SplitLines.js . I’m calling it on a variety of elements on pages, and some pages have multiple elements on the page which run the function. E.g. here are a few

DEFAULT_STYLES.splitHTML(".image-button > header .fsElementTitle");
    DEFAULT_STYLES.splitHTML(".home .school-box > header .fsElementTitle");
    DEFAULT_STYLES.splitHTML(".home .school-events > header .fsElementTitle");

I’ll clean up the code once I get this working.

My goal is to get something like this blue text, but it must be very flexible and responsive - https://fnlst.com/xxGaHg

So this means I need to account for people resizing the browsers, it being used over top of images/videos where there isn’t a solid background color (so a repeating linear gradient is out of the question).

The above code runs and calls the below code.

splitHTML(ele) {
    $(ele).each(function() {
      $(this).splitLines({
        tag: '<div class="line">',
        width: Math.round(parseInt($(ele).width()))
      });
      $(window).resize(function() {
        clearTimeout(window.resizedFinished);
        window.resizedFinished = setTimeout(function() {
          const lineWidths = [];
          const linePositions = [];
          $(ele).find(".line").each(function(i) {
            lineWidths.push($(this).outerWidth());
            linePositions.push($(this).position().top);
            if($(ele).find(".line").length - 1 === i) {
              for(let j=0;j<$(ele).find(".line").length;j++) {
                const eleWidth = $(ele).width();
                if(lineWidths[j] > eleWidth) {
                  DEFAULT_STYLES.unwrapHTML(ele);
                  break;
                }
                if(linePositions.some((val, i) => linePositions.indexOf(val) !== i)) {
                  DEFAULT_STYLES.unwrapHTML(ele);
                  break;
                }
              }
            }
          });
        }, 250);
      });
    });
  },

  unwrapHTML(ele) {
    $(ele).each(function() {
      $(this).find(".line").contents().unwrap();
      if($(this).is(":first-child")) {
        $(this).clone().addClass("cloned").prependTo($(this).parent());
      } else {
        $(this).clone().addClass("cloned").insertAfter($(this).parent().find("> *").eq($(this).index() - 1));
      }
      $(this).remove();
      $(ele+".cloned").splitLines({
        tag: '<div class="line">',
        width: Math.round(parseInt($(ele+'.cloned').width()))
      });
      $(ele+".cloned").removeClass("cloned");
    });
  }

How it works (or rather, how I believe it to work)…

  • splitHTML function gets called per element
  • I set the width (per an option in the plugin) - more on that in a bit.
  • I use a window resize event and wait until the user has finished resizing (250ms).
  • After the user is done resizing, I check 2 things: the individuals line WIDTH and the position offset relative to the nearest element with position: relative
  • The width check is to see if my individual lines (which have white-space: nowrap) is overflowing the container, and if so, I begin the step of deconstruction of the HTML and reapplying the plugin. So this part of the code checks users resizing smaller.
  • The position offset check is to see if a user is resizing their browser window larger and my inline-block lines have shifted up to be on a higher up row.
  • If either conditions are true, I then call the unwrapHTML function which basically removes the .line divs, clones the element, and calls the plugin back on that same element. I found the clone to be necessary due to issues I had.

The problem I have is that if I call this plugin on multiple elements, it doesn’t seem to work properly. If I call this…

DEFAULT_STYLES.splitHTML(".home .school-box > header .fsElementTitle");

This is found twice on my homepage. It works fine if both elements get this plugin. See this video.

However, if I call this twice…so e.g.

DEFAULT_STYLES.splitHTML(".home .school-box > header .fsElementTitle");
DEFAULT_STYLES.splitHTML(".home .school-events > header .fsElementTitle");

The .school-box is found twice on my page, and the school-events…just 1. But the act of calling this twice screws up my resizing.
https://fnlst.com/QFbKmg

The order of the calls matter. If I call both, and reverse the order, then the functionality is reversed - those 2 stacked boxes are fine, whereas my purple “Calendar Heading” does not work. Somehow I need to be able to call this on multiple elements. What am I missing? Sorry for the long post.

I think there’s a key flaw in this code to where the window resize event only gets called on the last element.

$(".image-button > header .fsElementTitle").each(function(i) {
      $(this).addClass("ib"+i);
      console.log("runs");
      DEFAULT_STYLES.splitHTML(".image-button > header .fsElementTitle.ib"+i, "ib"+i);
    });
  
  splitHTML(ele, tag) {
    $(ele).each(function(i) {
      const _ = $(this);
      const selector = ele.toString();
      console.log(selector);
      _.splitLines({
        tag: '<div class="line">',
        width: Math.round(parseInt(_.width()))
      });
      $(window).on("resize."+tag, function() {
        clearTimeout(window.resizedFinished);
        window.resizedFinished = setTimeout(function() {
          const lineWidths = [];
          const linePositions = [];
          _.find(".line").each(function(j) {
            lineWidths.push($(this).outerWidth());
            linePositions.push($(this).position().top);
            console.log(tag);
            console.log(lineWidths);
            console.log(linePositions);
            if(_.find(".line").length - 1 === j) {
              for(let k=0;k<_.find(".line").length;k++) {
                const eleWidth = _.width();
                if(lineWidths[k] > eleWidth) {
                  DEFAULT_STYLES.unwrapHTML(selector, tag);
                  break;
                }
                if(linePositions.some((val, l) => linePositions.indexOf(val) !== l)) {
                  DEFAULT_STYLES.unwrapHTML(selector, tag);
                  break;
                }
              }
            }
          });
        }, 250);
      });
    });
  },

  unwrapHTML(ele, tag) {
    $(ele).each(function() {
      const _ = $(this);
      console.log(typeof ele);
      console.log(ele);
      _.find(".line").contents().unwrap();
      // if(_.is(":first-child")) {
      //   _.clone().prependTo(_.parent());
      // } else {
      //   _.clone().insertAfter(_.parent().find("> *").eq(_.index() - 1));
      // }
      // _.remove();
      // console.log($(window))
      $(window).off("resize."+tag);
      DEFAULT_STYLES.splitHTML(ele, tag);
    });
  }

Console logs

runs
.image-button > header .fsElementTitle.ib0
runs
.image-button > header .fsElementTitle.ib1
ib1
[403.703]
[0]

I basically have it working now, but not very reusable-friendly. I could easily stop but I’m going to refactor my code a bit. The main issue was that resizingFinished stuff. Now I’m trying to undo the .each() logic when I call the initial function and make this more compact.

I had that resizingFinished stuff in there because I wanted it to run only once after users finished resizing but I ended up using debounce to just make the function run during resize with a 250ms delay. This way it doesn’t run all the time and it appears to have fixed the main issue.

Got it all fixed. So I basically call it like this

DEFAULT_STYLES.splitHTML(".image-button > header .fsElementTitle", "ib");

The first parameter is the element query, and the next is a custom “tag” to differentiate the elements.

splitHTML(ele, tag, ind) {
    $(ele).each(function(i) {
      let selector;
      if(ind === undefined) {
        $(this).addClass(tag+i);
        selector = ele.toString()+"."+tag+i;
      } else {
        selector = ele.toString();
        i = ind;
      }
      const _ = $(this);
      _.splitLines({
        tag: '<div class="line">',
        width: Math.round(parseInt(_.width()))
      });
      $(window).on("resize."+tag+i, debounce(function() {
        const lineWidths = [];
        const linePositions = [];
        _.find(".line").each(function(j) {
          lineWidths.push($(this).outerWidth());
          linePositions.push($(this).position().top);
          if(_.find(".line").length - 1 === j) {
            for(let k=0;k<_.find(".line").length;k++) {
              const eleWidth = _.width();
              if(lineWidths[k] > eleWidth) {
                DEFAULT_STYLES.unwrapHTML(selector, tag, i);
                break;
              }
              if(linePositions.some((val, l) => linePositions.indexOf(val) !== l)) {
                DEFAULT_STYLES.unwrapHTML(selector, tag, i);
                break;
              }
            }
          }
        });
      }, 250));
    });
  },

  unwrapHTML(ele, tag, ind) {
    $(ele).each(function() {
      const _ = $(this);
      _.find(".line").contents().unwrap();
      $(window).off("resize."+tag+ind);
      DEFAULT_STYLES.splitHTML(ele, tag, ind);
    });
  }
2 Likes

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.