Celebrate Excellence in Education: Nominate Outstanding Educators by April 15!
Found this content helpful? Log in or sign up to leave a like!
Hello,
A recent Canvas update left a lot of institutions without the ability to add additional resources to their Canvas Global Navigation. Previous discussions include:
Custom JavaScript/CSS Changes Adding custom menu items https://community.canvaslms.com/ideas/4034-custom-menu-items-for-new-ui
Source Code: https://github.com/robert-carroll/ccsd-canvas/tree/main/global-nav-custom-tray
This JavaScript will spawn and style (with CSS) DOM elements that mimic the Canvas global navigation tray, with animated easing for opening and closing the tray, and other interactions with the global navigation.
To create a tray that only shows up for certain roles, wrap the tray in an if condition
that checks for role.
2 role example
if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0) {
// tray source here
}
1 role example
if(ENV.current_user_roles.indexOf('student') >= 0){
$(document).ready(function() {
///* set tray title, icon, links and footer here *///
///* for user role based conditions see README *///
var title = 'Resources',
svg = '/pin-gregor-cresnar.svg',
trayLinks = [
{ href: 'http://www.example.com/your-library', title: 'Library', desc:'Optional text description' },
{ href: 'http://www.google.com', title: 'Google' },
{ href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional text description' }
],
footer = 'Optional footer text, put whatever you want here, or leave it blank.';
///* options are above for convenience, continue if you like *///
// tray source here
});
}
You can also create a tray that will appear for all users, but provide links (or even the tray name, icon, and footer), specific to the user role.
var title = 'Resources',
svg = '/pin-gregor-cresnar.svg',
// default links for all users
trayLinks = [
{ href: 'http://www.example.com/your-library', title: 'Library', desc:'Optional text description' },
{ href: 'http://www.google.com', title: 'Google' },
{ href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional text description' }
],
footer = 'Default footer for all users';
// these links are appended to the tray by user role
if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0){
trayLinks.push({ href: 'http://www.example.com/your-library', title: 'Teacher Library', desc:'Optional text description' })
trayLinks.push({ href: 'http://www.google.com', title: 'Google' })
footer = 'Teacher/Admin Footer overwrites default';
} else if (ENV.current_user_roles.indexOf('student') >= 0) {
trayLinks.push({ href: 'http://www.example.com/your-library', title: 'Student Library', desc:'Optional text description' })
trayLinks.push({ href: 'http://www.google.com', title: 'Google' })
footer = 'Student Footer overwrites default';
}
Pin by Gregor Cresnar from The Noun Project
https://creativecommons.org/licenses/by/3.0/
Solved! Go to Solution.
Hi, @chriscas
Oh my God, how embarrassing. That's what I get for jumping into dev mode without having completed a getting-started guide. Well, I suppose my idiocy is good news. I really appreciate your help. Was desperately looking for a cache clear or something.
Best,
Justine
This seems to be working great! I'm having trouble adding a conditional statement to differentiate between course roles. How would I add in something along the lines of...
if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0){
...
} else if (ENV.current_user_roles.indexOf('student') >= 0) {
...
} else {
}
Clint,
That's a great question. I am currently fine tuning the list above, but one of my next questions was going to be...
Would people prefer:
If the entire tray can run multiple instances (ie, Resources & Tools or Per Role) being different trays (and icons in the nav)...
or would they prefer if Tray Item Links could be separated by different roles, and placed in a single tray that adapts to roles?
What you have above would be pretty easy to customize, so maybe I wouldn't have to add too much.
Variations on that could look like the following, customized by the institution instead of bloating the code.
var title = 'Resources',
svg = 'linkto/menu.svg',
trayLinks = [
{ href: 'http://www.example.com/your-library', title: 'Library', desc:'Optional text description' },
{ href: 'http://www.google.com', title: 'Google' },
{ href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional text description' }
],
footer = 'Optional footer text, put whatever you want here, or leave it blank.';
if(ENV.current_user_roles.indexOf('teacher') >= 0 || ENV.current_user_roles.indexOf('admin') >= 0){
trayLinks.push({ href: '#teacher-admin1', title: 'Teacher/Admin Link 1', desc:'Optional text description' })
trayLinks.push({ href: '#teacher-admin2', title: 'Teacher/Admin Link 2' })
footer = 'Teacher Admin Footer';
} else if (ENV.current_user_roles.indexOf('student') >= 0) {
trayLinks.push({ href: '#student1', title: 'Student Link 1', desc:'Optional text description' })
trayLinks.push({ href: '#student2', title: 'Student Link 2' })
footer = 'Student Footer';
// default
} else {
trayLinks.push({ href: '#default-roles1', title: 'Default Roles 1', desc:'Optional text description' })
footer = 'Who goes there?';
}
///* options are above for convenience, continue if you like *///
Per role w/ unique icons per role would be pretty interesting! But, we've been working with just the one icon and the menu tailoring itself to the user role. Maybe 6 one way 1/2dozen the other. Unique icons could always be set to the same and changed as needed....
A lot of that can be easily handled in just the top code of the file, ie the tray title, and icon could be set in the user role conditions just like the example above, running in one instance.
Edit: Maybe at a later time.
Most likely, I will offer the ability to do both, I've already made improvements which would allow multiple instances to run, I don't see the code getting too cumbersome to make it work for multiple purposes. Will have to weigh the end user customization vs feature set.
Hi,
Hey, how would you shoehorn a link in the "People" feature that only the Teacher course role would see? Right now, with the code below, both students and students see the link(s) - where in the adjacent "Grades" lines there is differentiation (two different pages, Teacher Grades and Student Grades, we know... People seems to be the same page just with a couple of buttons dropped in there for Teacher). -Thanks!
--
I wanted to point out one major difference for anyone who uses this.
While I tried to keep the end user configuration as close to the original contribution, I added the optional description value for each TrayLink. So please note that you should be able to copy/paste TrayLinks from your existing solution, after replacing key/val with href/title.
Old
trayLinks = [
{key: 'http://www.example.com/your-library', val: 'Library'},
{key: 'http://www.google.com', val: 'Google'},
{key: 'http://www.example.com/help-desk', val: 'Help Desk'}
];
New
trayLinks = [
{ href: 'http://www.example.com/your-library', title: 'Library' },
{ href: 'http://www.google.com', title: 'Google' },
{ href: 'http://www.example.com/help-desk', title: 'Help Desk', desc:'Optional text description' }
],
Thank you for making this code available.
My institution is a new Canvas customer and we are looking to use it. I am also new to JavaScript so please bear with me as I struggle with what may seem like simple aspects of JS coding. Hopefully my struggles, my questions, and your answers will also help others.
In our beta environment, I simply tried copying your 20 lines of Tray for everyone, links by role code (this seemed to be the best place to start, please let me know if another option would be better) into a JS file, uploaded the JS file into the Canvas theme, and nothing happened.
My plan was to see what that did and then make any necessary adjustments (e.g. changing links) but nothing happened.
Based on that I have three questions:
Thank you for your help.
Hi Douglas,
The 20 lines in the comment above is a usage example to customize the default behavior of a larger script, based on features people expected/preferred from another project that no longer works.
I will do my best to get you started and answer any questions.
First, the entire source code for the project is available on Github, here ccsd-canvas/global-nav-custom-tray, including a README on setup, which I'm sure isn't going to be the easiest to understand if you are new to JavaScript. I recommend reviewing it after we get some plug-n-play functionality working for you.
Second, you need the whole thing. You can cheat off my paper here starter-tray · GitHub, where I've conveniently copied and pasted all the elements you requested above into a single script. Click the RAW button on the right, copy and paste (adding) it into your Canvas Themes - JavaScript file.
You will also need to upload the contents of the CSS file in the repository to your Canvas Themes - CSS file, here ccsd-canvas/global-nav-custom-tray.css
Finally, the SVG image is a bit tricky and there are lots of options. I've started you off by creating a Gist for the pin-icon with the SVG paths built in and shared via RawGit... so that when you use the Starter Tray code it will just work. This is a quick and dirty solution and I wouldn't recommend it for Production use, because it's not organized. We use Amazon Web Services for various reasons, mostly because it easy for us to host Secure files to push back into Canvas, often with these kinds of JavaScript hacks. Amazon S3 makes this kind of hosting cheap and easy. You may also check with whatever department or team manages your institutions web services/hosting/web site and see if they can start providing a Secure space to host images. To work in Canvas the files need to be served via HTTPS so users don't get mixed content warnings or the Browser doesn't exclude the content.
Regarding InstUI and those icons... I wasn't aware of this product until recently and from what I have played with it doesn't appear the components are available through Canvas Themes. They are designed to be used and compiled into an LTI or web service that gets plugged back into Canvas. Fortunately, SVG images are text and Canvas is Open Source. You can probably get away with copying and hosting an icon from InstUI as long as you give credit and read the license... instructure-ui/LICENSE at master · instructure/instructure-ui · GitHub
I couldn't complete this reply without making the piggy bank pink, inst-ui-icon-bank-svg · GitHub
Hello carroll-ccsd,
I would like to thank you again for your help. I was able to get your code working in our Canvas environment. However, we have decided to go in a different direction so that we have more flexibility and so we could reduce the risk of something breaking or not working when their is an update.
We ended up using JS code from Adding custom menu items and/or Help With Custom Menu Icons and Script to make a new button that does the following:
Ultimately we decided that if we were going to use code that was not supported by Canvas, we wanted to reduce the risk of something "breaking". Another reason is because we did not want to modify any CSS or JS code in the event that we wanted to add an additional item; which we would have had to do if we used the code in this thread.
While we did not end up using this code, it helped me to learn more about JS, CSS, and Canvas and hopefully your assistance will also help others.
Thank you again,
@dbrace ,
That's great!
I'm glad you found a solution that works for you, and I fully understand that nothing is one-size-fits-all. Truthfully, we don't even use this feature ourselves, because we already have some help menu hacks in place and a 'Hub' course that provides some of the same features you describe above.
Hey Robert, what do you think it would take to make the "RIght-Sidebar Logo" a clickable image/to embed a link in that space?
I might be misunderstanding you...
Are you looking for something like this, but using an image?
This is displayed on every page.
The Right Sidebar Logo only shows up on the Dashboard...
We can do either, or a combination. :smileygrin:
Hey - that's pretty handy too! What I was getting at, though, was embedding a link 'into' the actual image. It's ok that it would only show on the dashboard.
Replace the # for the URL, target blank is optional.
// http://api.jquery.com/wrap
$('.ic-sidebar-logo__image').wrap('<a href="#" target="_blank"></a>');
// plain javascript - no jQuery
(function () {
var img = document.getElementsByClassName('ic-sidebar-logo')[0].innerHTML
var wrap = '<a href="#" target="_blank">'+ img +'</a>'
document.getElementsByClassName('ic-sidebar-logo')[0].innerHTML = wrap
})();
Thanks Robert. I can tget it to work though, I think I'm missing something.
Which one are you trying, jQuery or plain/vanilla JS?
Does it give an error in the console?
Can you take a screenshot of the element using Developer Tools, like this... (don't hide it with the menu like I did)
...try to show me anything around or nested within that element by expanding ▶
Thank you for this. One question. I'd like to adjust the menu based on the current sub-account. Is that possible as is, or do I need to add my own call to get the account_id from the current course context (or some other way).
There are scenarios in which a user is only associated with one sub-account, and start off in that theme, but I'm not sure how to derive that context either.
Without the time test this with code right now, you could either, place a different file with it's own config at each sub account – or place a master at the root theme and pass the links to it at each sub account. Displaying the menu if/when there are additional links. Here's an example of passing variables from Global to Sub Account, Cascading Stylesheets/Javascript from Main Account to Sub Accounts
If users and users with multiple accounts get trickier, it's likely you'd need a more dynamic/role based solution you can't get with Themes. In which case you'd probably need to check out, instructure-ui : UI libraries made by Instructure Inc. (5.41.1) for a InstUI Nav Tray ... LTI.
It looks like with the last production release custom navigation options are only showing for the user when looking at their Canvas dashboard. Has anyone else noticed this? (Anyone got an idea on how to fix it?)
Dashboard.... ... any other page-->
Installed globally I'm not seeing an issue drilling down from the Dashboard.
Are you installing at a sub account, and then not seeing the icon when navigating within that sub account?
I think I’ve got it. More precisely, when viewing a Canvas “Page” (wiki page w/in Canvas, etc.) the custom global options don’t display. Odd… It’s a change from the past, for sure.... "Modules", "People", "Files" and custom global options display. But a "Page" and they don't.
Navigation and routes shouldn't make a difference to global javascript loaded in themes, unless there is additional logic that specifies what to do with those window location or pathnames.
Where did you install the script, global or sub account?
Did you add additional logic?
Are you importing the JS or directly appending it to your theme files?
Give it a shot. Someone else here just confirmed in our instance.
Dashboard Course, Pages, All Pages, Page
Where did you install the script, global or sub account? Global
Did you add additional logic? Nope... though we have some other stuff in there from/for vendors' integrations
Are you importing the JS or directly appending it to your theme files? Just uploading it through themes...
Are you having the same problem on test?
Yes -
There's a chance code to this google analytics piece may be getting in the way...
https://community.canvaslms.com/docs/DOC-9211-how-to-set-up-google-analytics-for-canvas
I'm not seeing flags in my inbox for each of your replies... sorry if it takes a bit for me to reply. I'm also trudging through some debugging today to give feedback for an issue I made on another OSS.
I can't do much to support GA alongside the script, but they should be fine together.
Are they each in their own? ($(document).ready(function() {}))
If you're open to it, you can DM me a paste/file/github gist with your code? I can give it a quick look.
@JACOBSEN_C , the issue appears to be in the 2 blocks of your file for
if (typeof ENV["WIKI_PAGE"] !== 'undefined')
TypeError: $(...).accordion is not a function
...and so it begins...
https://community.canvaslms.com/docs/DOC-16493-canvas-release-notes-2019-04-20#comment-140756
So you're say'n this is in the wake of the move to the 2.0 style guide?
I can't put enough resources on this at the moment to identify an actual cause, but the function doesn't work in your file. However, if I run $("#styleguide-tabs-demo-regular").tabs(), after the page is loaded it works. This happens on our production instance (but I import jQueryUI), and on test where I disabled our custom code.
Alternatively, if it is working, you might want to change your code to detect when jQueryUI is available, not when the wiki page content is.
But with the comments in the Release thread, we should probably start advising people stop hacking their way around this, and start taking tinier steps to move past it.
Thanks. Yesterday I just took the respective javascript out of our theme. Bite the bullet, see what happens. Our faculty and designers only ventured into styles on occasion, and we're just about done with the term. THanks for the help though, Robert. We appreciate it for sure.
Welcome Clint!
Canvas announced back in early 2017 that they were deprecating the jQuery UI and later that accordions were going to be the first to go. I thought they had already removed the accordions, so the fact that it was still working is more of a surprise than it's not now. If the accordions are the only thing to have disappeared right now, then that's consistent with what they have been saying.
Kona has a training courses that still has tabs and they're still working, although Canvas throws an error message in the log that has been there since at least April 2017.
instructure.js:128 Deprecated use of magic jQueryUI widget markup detected:
You're relying on undocumented functionality where Canvas makes jQueryUI widgets out of rich content that has the following class names: .dialog, .draggable, .resizable, .sortable, .tabs.
Canvas is moving away from jQueryUI for our own widgets and this behavior will go away. Rather than relying on the internals of Canvas's JavaScript, you should use your own custom JS file to do any such customizations.
I am not using a tray but I have previously commented in this thread about what I have done. I do not have a lot of coding experience but I have used the following code (attached as a TXT file after original comment) to add a "Resources" button (which links to a public course in our Canvas environment) to our side navigation and it seems to still be working after the latest production release.
The icon-pin code that I used I came across from https://instructure.design/#iconography; which from what I understand is where (or what) we should be going to (or doing) for proper design
I understand that all of us only have so much information but should I prepare for this code (including the icon assigned to it) to stop working in the near future?
// Add Resources Button to Global Navigation Tray
var styleAdded = false;
function addMenuItem(linkText, linkhref, icon, target) {
var iconHtml = '',
itemHtml,
linkId = linkText.split(' ').join('_'),
iconCSS = '<style type="text/css">' +
' i.custom_menu_list_icon:before {' +
' font-size: 27px;' +
' width: 27px;' +
' line-height: 27px;' +
' }' +
' i.custom_menu_list_icon {' +
' width: 27px;' +
' height: 27px;' +
' }' +
' body.primary-nav-expanded .menu-item__text.custom-menu-item__text {' +
' white-space: normal;' +
' padding: 0 2px;' +
' }' +
'</style>';
if (icon !== '') {
// If it is a Canvas icon
if (icon.indexOf('icon') === 0) {
iconHtml = '<div class="menu-item-icon-container" role="presentation"><i class="' + icon + ' custom_menu_list_icon"></i></div>';
// for an svg or other image
} else if (icon !== '') {
iconHtml = '<div class="menu-item-icon-container" role="presentation">' + icon + '</div>';
}
}
// Process Target
if (target !== undefined && target !== null && target !== '') {
target = ' target="' + target + '"';
} else {
target = '';
}
// Build item html
itemHtml = '<li class="ic-app-header__menu-list-item ">' +
' <a id="global_nav_' + linkId + '" href="' + linkhref + '" class="ic-app-header__menu-list-link" ' + target + '>' + iconHtml +
' <div class="menu-item__text custom-menu-item__text">' + linkText + '</div>' +
' </a>' +
'</li>';
$('#menu').append(itemHtml);
// Add some custom css to the head the first time
if (!styleAdded) {
$('head').append(iconCSS);
styleAdded = true;
}
}
addMenuItem('Resources', '<insert desired URL>', 'icon-pin', '_blank');
@dbrace ,
The issue is with Canvas deprecating the jQueryUI styleguide, mostly for content pages. The custom menu or instructure-ui icons shouldn't be a problem in your example.
For clarification, there is no issue with the Global Nav Menu code at this time.
Hey carroll-ccsd, got an idea on how to remove the account navigation menu from admin roles with limited permissions via CSS?
To participate in the Instructure Community, you need to sign up or log in:
Sign In