Hiding LTIs from Account/Admin Navigation Menu in a Specific Subaccount

Jump to solution
NickChevalierUT
Community Explorer

Hi everyone,

Long-time reader and browser, first-time poster!  😀

I'm one of the Canvas Account Admins at our institution, and I've been tasked with giving a member of our institution a subaccount admin role with very narrow parameters—easy enough through permissions. However, we've discovered we have some LTIs installed (with placement in the Account Navigation) that, if this user visits those pages, they can edit things we don't want them to be able to.

After consulting with our CSM, unfortunately our only option is to use custom JavaScript to hide those LTI links within that specific subaccount. On one hand, this is fine because the admins on our team who would normally access those LTIs at the subaccount level are still able to at the root account, and elsewhere in other accounts if needed—hiding them from all admin users only in this specific subaccount shouldn't be an issue. On the other hand, I've seen custom CSS and JS used at other institutions to highly detrimental effect, so it's something I'm extremely wary about and cautious of.

That said, while I'm admittedly no coder or developer, I've enlisted the help of ChatGPT and have been testing in beta, and have found some JS that, so far, seems to work well:

 

// Defer until all page elements load
window.onload = function () {
    // Select and hide the child elements of the div with the ID "left-side"
    var leftSideElement = document.getElementById('left-side');

    if (leftSideElement) {
        var ltiSelectors = '.context_external_tool_332, ' +
                           '.context_external_tool_333, ' +
                           '.context_external_tool_573, ' +
                           '.context_external_tool_154';

        var ltiElements = leftSideElement.querySelectorAll(ltiSelectors);

        ltiElements.forEach(function (ltiElement) {
            ltiElement.style.display = 'none';
        });
    }
};

 

This actually works really well! However, the problem I'm running into is that one of the LTIs—Credentials—also uses the same class defined in the JS above (context_external_tool_154) in both the Account Navigation Menu and in individual Course Navigation Menus. That means, within this specific subaccount, if I want to hide the admin-level Credentials LTI (where the user could edit things), it also hides the course-level Credentials link in the course navigation menu. This can’t work, because we want faculty in this subaccount to have the option to use Credentials if they choose to.

Normally, my next step would be, "ok, let's figure out how to target the Account Navigation Menu and exclude the Course Navigation Menu." Problem is...Canvas doesn't seem to differentiate them at all in terms of HTML on the page. Here's the HTML structure of the Account Navigation Menu:

 

<div id="main" class="ic-Layout-columns">
        <div class="ic-Layout-watermark"></div>
        <div id="left-side"
          class="ic-app-course-menu ic-sticky-on list-view"
          style="display: block"
          >
          <div id="sticky-container" class="ic-sticky-frame">
            <nav role="navigation" aria-label="Admin Navigation Menu"><ul id="section-tabs">...Nav Links Here...</ul></nav>
          </div>
        </div>

 

And here's the HTML structure of the Course Navigation Menu:

<div id="main" class="ic-Layout-columns">
        <div class="ic-Layout-watermark"></div>
        <div id="left-side"
          class="ic-app-course-menu ic-sticky-on list-view"
          style="display: block"
          >
          <div id="sticky-container" class="ic-sticky-frame">
              <span id="section-tabs-header-subtitle" class="ellipsis">2023 Fall Semester</span>
            <nav role="navigation" aria-label="Courses Navigation Menu"><ul id="section-tabs">...Nav Links Here...</ul></nav>
          </div>
        </div>

The only difference I'm seeing is in the "aria-label" attribute, but in all my testing, there's no way (at least, none that I've found to work so far) to target the <nav> with the "Admin Navigation Menu" aria-label specifically.

I've tried to use other JS to try and add an id or class to one of the nav menus to try and differentiate them, but none of that has worked so far either.

Has anyone else tried anything similar? Is there something in my code I'm missing, or some other approach I can try?

0 Likes
1 Solution
chriscas
Community Coach
Community Coach

Hi @NickChevalierUT,

I usually handle this by having if statements that check the URL and only run the code if in an appropriate place (like the accounts area in this case).  There may be an alternate way to do this, but I think the following should work:

// Defer until all page elements load
window.onload = function () {
    if (/^\/accounts\/[0-9]+/.test(window.location.pathname)) {
    // Select and hide the child elements of the div with the ID "left-side"
        var leftSideElement = document.getElementById('left-side');
    
        if (leftSideElement) {
            var ltiSelectors = '.context_external_tool_332, ' +
                               '.context_external_tool_333, ' +
                               '.context_external_tool_573, ' +
                               '.context_external_tool_154';

            var ltiElements = leftSideElement.querySelectorAll(ltiSelectors);

            ltiElements.forEach(function (ltiElement) {
                ltiElement.style.display = 'none';
            });
        }
    }
};

Hope this helps!

-Chris

View solution in original post