0

Is there a jQuery or vanilla JS function that will group items of matching text content, without me prompting class names, elements, etc?

More specifically for this project, I need to group modules together, and I do not know how many will eventually be made. I can name them all similarly, say "Module 1 DOC, Module 1 XLSX, Module 1 PPT, Module 2 DOC, Module 2 XLSX, Module 2 PPT," etc, so it could be something like:

$("div#page").each(function(index) {
   // check titles for generic matching content 
   if ($(this).find("h1:contains('*[words-that-match]')").length > 0) { 
      
   }
});

or [same-title] something like that? I'm not sure what the syntax would look like.

I apologize that my JS/JQ knowledge is so lacking, I am pretty new to this. Thanks in advance!

Justine
  • 49
  • 6

2 Answers2

1

If you can, I recommend separating your grouping logic from the display, that way you can easily change the label without impacting the logic.

For example instead of only having a name make it into an object that looked something like:

{
  displayName: "Module 1 PPT",
  fileType: "PPT"
}

Then you could use the JS Array.reduce function to group objects together.

var groupBy = function(xs, key) {
  return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
  }, {});
};

const moduleFiles = [
  {
    displayName: "Module 1 PTT",
    fileType: "PTT"
  },{
    displayName: "Module 1 DOC",
    fileType: "DOC"
  },{
    displayName: "Module 2 PTT",
    fileType: "PTT"
  },{
    displayName: "Module 2 DOC",
    fileType: "DOC"
  }
]

console.log(groupBy(moduleFiles, 'fileType'));
The above code was copied from: Another SO answer
Hassan Mahmud
  • 484
  • 4
  • 13
  • Thanks @hassan-mahmud. I think your answer is moving in a better direction than my janky solution, so I'll mark it correct. I'm unfortunately so unfamiliar with this method I couldn't figure out how to make it perform the way I needed. It has given more more to learn after I finish this script! – Justine Aug 15 '21 at 22:27
0

EDIT: The solution I used ended up using relied on a using a .nextAll().first() element search and targeting with a fake class. Disclosure: I'm working front-end in an LMS without access to any stylesheets or PHP.

$(document).ready(function(index) {
   var URL = "li.modtype_url"
   var BOOK = "li.modtype_book"
   var H5P = "li.modtype_h5pactivity"

   // select only items titled module...
   if ($(this).find("p.instancename:contains('module')").length > 0) {

      //-- CHANGE THE URL MODTYPE TITLE
      $(URL).each(function(index) {
         // variables
         let oldTitle = $(this).find(".snap-asset-link")
         let newTitle = $(this).find(".snap-asset-content .contentafterlink a.tile-title")
         // save the title, remove it, and add to new location
         oldTitle.remove();
         newTitle.append(oldTitle);
         /// hide or remove additional unwanted asset styling
         $(this).find(".snap-assettype").css("height", "0px");
         $(this).find(".snap-asset-content .no-overflow").removeClass("no-overflow"); 
      });

      //-- MOVE ICONS
      $(this).each(function () {
         var oldIcon = $(".snap-header-card .snap-header-card-icons .snap-asset-completion-tracking img")
         var newIcon = ".snap-asset-content .contentafterlink div.tile-completion"
         // first of set
         $(this).each(function () {
            // find the first of each, add empty class to mark
            let oldIcon_URL = $(URL).first().find(oldIcon).addClass("moved")
            let oldIcon_BOOK = $(BOOK).first().addClass("moved").find(oldIcon)
            let oldIcon_H5P = $(H5P).first().addClass("moved").find(oldIcon)
            let newIconLocation = $(URL).first().addClass("moved").find(newIcon)
            // relocated all moved-targeted items to new location
            newIconLocation.append(oldIcon_URL).append(oldIcon_H5P).append(oldIcon_BOOK);
         });
         //next of each modtype, repeated
         setInterval(function() {
            // find the first non-targeted of each, add empty class to mark
            let oldIcon_URL = $("li.modtype_url:not(.moved)").first().find(oldIcon).addClass("moved")
            let oldIcon_BOOK = $("li.modtype_book:not(.moved)").first().addClass("moved").find(oldIcon)
            let oldIcon_H5P = $("li.modtype_h5pactivity:not(.moved)").first().addClass("moved").find(oldIcon)
            let newIconLocation = $("li.modtype_url:not(.moved)").first().addClass("moved").find(newIcon)
            // relocated all moved-targeted items to new location
            newIconLocation.append(oldIcon_URL).append(oldIcon_H5P).append(oldIcon_BOOK);
         });
      });
      
   };
});

This solution is a) majorly convoluted and b) while it is an automated process, is relies modules to cascade (ie 1, 2, 3 only) to group. Not ideal.

Justine
  • 49
  • 6