Character count and element size via Javascript
New here? Learn about Bountify and follow @bountify to get notified of new bounties! x

I teach graphic design and I want my students to make design decisions based on the readability of text. To help them I cobbled together some Javascript that counts the 45–75 character range of any text within an element that they add an id to. You can sorta see in action in this pen https://codepen.io/garyrozanc/pen/LddrXz

I'm looking for someone to rewrite the Javascript so any element on the page can be clicked and the 45-75 character count range will be highlighted without having to add any classes or ids. So any element on the page can be clicked. Any inline HTML tags need to be ignored by the character counter within the element.

I also want an additional pop-up that gives the pixel dimensions of the element containing the text. Here is a nonworking visual mockup. https://codepen.io/garyrozanc/pen/eLezrg

This lets my students identify when to create a new breakpoint based on readability and have actual dimensions to work from. If you have any questions let me know so I can make this as clear as possible as to what I need.

I may be away from my computer for the rest of the night, so I may not see potential solutions until tomorrow morning.

For an extra $10 tip, can anyone make it so this https://codepen.io/anon/pen/WYBdzM pen turns off the text highlighting when the element is clicked a second time? Also, can you make the pixel dimensions display the size of the element containing images too?
imokyourok 11 days ago
Thanks for awarding me the bounty so quickly! I've updated the pen and my solution to include highlight toggling. Adding the pixel dimension to images would be non-trivial and I'd rather let someone else try it out. You might want to make a new bounty for it, if you want anyone else to be aware of your request.
CyteBode 11 days ago
Hey, I cleaned up my code and managed to add the pixel size for images. It wasn't quite as hard as I thought it would be, I just had to change how things were done. The CodePen is in the updated solution.
CyteBode 10 days ago
awarded to CyteBode
Tags
javascript

Crowdsource coding tasks.

1 Solution


Note: This uses mark.js. Here's why: https://stackoverflow.com/a/34614703

Javascript

(function() {
  var sizeSpans = [];

  function updateSizeSpan(ele, span) {
    var w = ele.offsetWidth;
    var h = ele.offsetHeight;
    span.innerHTML = w + "×" + h;
  }

  function wrapOutline(ele) {
    if (ele.classList.contains("outline") || 
        ele.classList.contains("size")) {
      // To avoid nesting outlines or adding an outline to the size
      return;
    }

    // Size span
    var span = document.createElement("span");
    span.classList.add("size");
    updateSizeSpan(ele, span);
    sizeSpans.push(span);

    // Outline
    var outline = document.createElement("div");
    outline.classList.add("outline");

    // Wrap the element with the outline div
    var parent = ele.parentNode;
    parent.replaceChild(outline, ele);
    outline.appendChild(ele);
    outline.appendChild(span);

    // Unwrapping handler
    outline.addEventListener("click", function (e) {
      var outline = e.target;
      while (!outline.classList.contains("outline")) {
        // Make sure to deal with the outline div directly
        outline = outline.parentNode;
      }
      var ele = outline.firstChild;
      var parent = outline.parentNode;

      // Unwrap the element
      outline.removeChild(ele);
      parent.replaceChild(ele, outline);

      // Remove span from sizeSpans;
      var span = outline.lastChild;
      sizeSpans.splice(sizeSpans.indexOf(span), 1);

      // Un-highlight the text
      var instance = new Mark(ele);
      instance.unmark();

      e.stopPropagation();
    });
  }

  function highlight(ele) {
    var instance = new Mark(ele);
    instance.markRanges([{start: 45, length: 30}], {
      element: "span",
      className: "highlight"
    });
  }

  var all = document.body.getElementsByTagName("*");
  for (var i = 0; i < all.length; i++) {
    if (all[i].parentNode !== document.body) {
      continue;
    }

    all[i].addEventListener("click", function(e) {
      var ele = e.target;

      if (ele.tagName == "DIV" || ele.tagName == "BODY") {
        // Avoid dealing with divs or the body tag
        return;
      }

      while (ele.parentNode &&
             ele.parentNode.tagName != "DIV" &&
             ele.parentNode.tagName != "BODY") {
        // Recurse up to avoid dealing with the smaller leaf nodes
        ele = ele.parentNode;
      }

      highlight(ele);
      wrapOutline(ele);
    });
  }

  if (typeof(document.documentElement.clientWidth) != 'undefined') {
    var $w = document.getElementById('w'),
        $h = document.getElementById('h');
    $w.innerHTML = document.documentElement.clientWidth;
    $h.innerHTML = ' &times; ' + document.documentElement.clientHeight;

    window.onresize = function(event) {
      // Update the size in the upper-right corner
      $w.innerHTML = document.documentElement.clientWidth;
      $h.innerHTML = ' &times; ' + document.documentElement.clientHeight;

      // Update the size spans
      for (var i = 0; i < sizeSpans.length; i++) {
        var span = sizeSpans[i];
        var ele = span.parentNode.firstChild;
        updateSizeSpan(ele, span);
      }
    };
  }
})();

Additional CSS

.outline {
  outline: 1px solid rgba(194, 240, 177);
  padding: 0;
  position: relative;
}

.count {
  background-color: rgba(194, 240, 177, 0.45);
}

.size {
  background-color: red;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

CodePen: https://codepen.io/anon/pen/EOBoQr

Edit 1: Added toggling of the highlight.

Edit 2: Merged the two halves more cohesively and added pixel size for images.

Edit 3: Added changing of the pixel dimension displays on screen resize.

Thanks for the tip!
CyteBode 11 days ago
Thanks for adding the dimensions to the images. I'm going to leave you a tip for that as promised. Before I do leave the tip, I have another task that I'm willing to tip for. How difficult would it be to make the pixel dimension display change on screen resize like the counter in the upper right-hand corner changes as the screen is resized?
imokyourok 10 days ago
It shouldn't be too hard. I could maintain the list of the size span's and update them in the window.onresize function. I can't really work on it right now, but I should have something by this evening.
CyteBode 10 days ago
That's fine. I'm working on other stuff today anyway. I'd like to tip all at once for both if that's OK.
imokyourok 10 days ago
I've added the new feature. The pen is a new one, so make sure you're not accessing the old one.
CyteBode 10 days ago
Perfect! I just tipped you for both updates. Thank you for your work on this.
imokyourok 10 days ago
Thanks for the additional tip! I'm glad to hear you're satisfied.
CyteBode 10 days ago